Spring框架系列(一)-整体架构
来源:互联网 发布:qq windows phone版 编辑:程序博客网 时间:2024/05/21 09:24
附上示例程序的github地址:https://github.com/bjtudujunlin/SpringDataExample
一、Spring设计目标
Spring设计的初衷在于提供一套轻量级的应用开发框架,解决开发者在应用开发中的共性问题。这句话有两个关键字,一是“轻量级”,二是“共性问题”。为啥叫“轻量级”呢,Spring框架本身不能给你解决业务问题,也没有相关库,只是提供了一个框架,让你的程序更加健壮、易于维护,你看到的Spring MVC、Spring Data之类的都是基于Spring框架的组件,不属于Spring框架内容。那么“共性问题”有啥呢,耦合,还是耦合,日常程序开发中,有两类耦合问题经常遇见,一是类与类关系的耦合,软件开发中,类与类的“组合”关系普遍存在,比如B类有属性B1是A类的实例,在B中需要对B1进行初始化操作,Spring中的IOC容器提供了配置文件的方式对B类进行管理,包括初始化操作,配置属性B1的值等等。二是服务与服务关系的耦合,比如现在有一个数据库操作类C,现在我们想为这个类加上权限检测的功能,只有具有特定权限的人群才能调用数据库操作类的方法,一般处理是在类C中调用权限检测方法,这样就导致了服务之间的耦合,违背了“单一职责原则”,Spring提供了AOP方法,以非侵入式的方式解决这种耦合问题,保持了服务的独立性,又满足了业务的需求。
二、Spring整体架构
Spring整体架构如下图所示,核心模块是Spring IOC和Spring AOP模块,其它的模块都是基于这两个核心模块进行开发,然后以组件的方式集成进来的。这里先重点介绍核心的IOC和AOP模块,其它组件留在后面的组件环节进行详细介绍。
图 1
三、Spring核心模块
1. IOC模块
IOC模块其实是一个IOC容器,提供了对Bean进行管理的功能,依赖于这个功能,解决了类与类关系的耦合。下图比较适合解释IOC容器。由于引进了中间位置的“第三方”,也就是IOC容器,使得A、B、C、D这4个对象没有了耦合关系,齿轮之间的传动全部依靠“第三方”了,全部对象的控制权全部上缴给“第三方”IOC容器,所以,IOC容器成了整个系统的关键核心,它起到了一种类似“粘合剂”的作用,把系统中的所有对象粘合在一起发挥作用,如果没有这个“粘合剂”,对象与对象之间会彼此失去联系,这就是有人把IOC容器比喻成“粘合剂”的由来。
图 2
有了前面的基础,我们再来看看IOC(Inversion of Control)——控制反转的意思。为啥叫控制反转呢?因为它涉及到控制权在谁手里的问题,举个例子,引入IOC容器之前,对象A依赖于对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B,控制权都在A自己手上。那么引入IOC容器之后呢,对象A与对象B之间失去了直接联系,所以,当对象A运行到需要对象B的时候,IOC容器会主动创建一个对象B注入到对象A需要的地方。可以看见创建对象B的控制权由A转移到了IOC容器,控制权反转了。
还有一个平时容易混淆的概念DI(Dependence Injection)——依赖注入,这个和IOC有什么关系呢。前面我们说了IOC容器会主动创建一个对象B注入到对象A需要的地方,DI其实就是IOC实现控制反转的方法。
下面举一个IOC具体的例子,这里先采用XML的方式,这种方式比较复杂,但是能更好的理解spring的IOC配置,后续会补充java配置方式。
a) 建立maven的java工程,并添加spring-core的依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
b) 建立Person类
public class Person {
private Stringname;
private Stringage;
private Regionregion;
public String getName() {
returnname;
}
public void setName(String name) {
this.name =name;
}
public String getAge() {
returnage;
}
public void setAge(String age) {
this.age =age;
}
private Stringdiscribe;
public Person(Regionregion,Stringdiscribe){
this.region =region;
this.discribe =discribe;
}
public void Introduce(){
System.out.println("I am " +name +",I comefrom " +region +"my age is" +age);
System.out.println(discribe);
}
}
c) 建立Region类
public class Region {
private Stringprovince;
private Stringcity;
public StringgetProvince() {
returnprovince;
}
public void setProvince(String province) {
this.province =province;
}
public String getCity() {
returncity;
}
public void setCity(String city) {
this.city =city;
}
@Override
public String toString(){
returnprovince +" " +city;
}
}
d) 在resource下面新建spring的xml配置文件spring-config.xml
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context">
<!-- 配置细节 -->
<!-- bean如果没有指定ID,会生成默认ID,形式为“类名#0”,0是计数 -->
<beanid="person"class="iscas.springstudy.Person">
<!-- 配置构造函数,按照配置函数从左到右的顺序,ref标签表示参数为指定id的bean,value标签表示参数值 -->
<constructor-argref="region-a"></constructor-arg>
<constructor-argvalue="a funny man"></constructor-arg>
<!-- 配置属性,name对应属性名,value对应属性值,属性中也可以右ref标签,跟构造函数是一样的意思
需要注意的是配置属性要求该属性必须右getter方法和setter方法-->
<propertyname="name"value="liming"></property>
<propertyname="age"value="19"></property>
</bean>
<beanid="region-a"class="iscas.springstudy.Region">
<propertyname="province"value="beijing"></property>
<propertyname="city"value="haidian"></property>
</bean>
</beans>
e) 加载xml文件,生成beanfactory,获取bean,并调用其中方法
XmlBeanFactory factory =newXmlBeanFactory(newClassPathResource("spring-config.xml"));
Person person = (Person)factory.getBean("person");
person.Introduce();
f) applicationcontext方式加载xml文件
beanfactory类现在已经过期了,applicationcontext类继承自beanfactory,能够提供比beanfactory更多的支持,所以在看看applicationcontext怎么调用。首先需要在maven中添加applicationcontext依赖。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
代码中用applicationcontext取代beanfactory即可,改变如下
ApplicationContext application =newClassPathXmlApplicationContext("spring-config.xml");
Person person = (Person)application.getBean("person");
person.Introduce();
2. AOP模块
在软件开发中,散布于应用中多处的功能被称为横切关注点(cross-cutting concern)。通常来讲,这些横切关注点从概念上是与应用的业务逻辑相分离的(但是往往会直接嵌入到应用的业务逻辑之中)。把这些横切关注点与业务逻辑相分离正是面向切面编程(AOP)所要解决的问题。下面这个图可以加深理解。
图 3
上图中,CourseService、StudentService和MiscService都属于业务服务,比如CourseService就是课程管理服务。现在需要为CourseService服务加上安全校验功能,传统的做法是创建一个安全类,然后在CourseService服务中需要安全校验的地方进行调用,这样逻辑简单,但是该方式是侵入式的,改变了CourseService服务本身的代码,CourseService服务和安全类耦合起来,比如我以后将CourseService服务换到别的地方去用,要么删除安全功能,要么把安全类也带上。同样的StudentService、MiscService都用到了同样的安全类。这里的安全类就是横切关注点。要解决前面这个侵入式的问题,我们就需要引入AOP的思想,既满足上述功能需求,又是非侵入式的。
理解AOP需要理解以下几个概念:
a) 通知(Advice),切面必须要完成的工作。在AOP术语中,切面的工作被称为通知。Spring切面支持的最小粒度是方法,可以应用5种类型的通知:
前置通知(Before):在目标方法被调用之前调用通知功能;
后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么;
返回通知(After-returning):在目标方法成功执行之后调用通知;
异常通知(After-throwing):在目标方法抛出异常后调用通知;
环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。
b) 连接点(Join point),连接点是在应用执行过程中能够插入切面的一个点。比如Spring AOP只能支持到方法粒度,所以类型的方法可以作为连接点,AOP可以在方法上插入切面,监听方法的调用,并触发通知。
c) 切点(Poincut),一个切面并不需要通知应用的所有连接点,选择的连接点就是切点。连接点表示有这个能力,而切点就是已经选择的连接点。
d) 切面(Aspect),切面是通知和切点的结合。通知和切点共同定义了切面的全部内容。
总结起来,AOP无非就干了两件事情,选择连接点作为切点,插入切面对切点进行监听。当切点满足通知条件时,通知触发。
Spring AOP的基本概念到这儿解释完了,考虑AOP内容还有些,放在下一章节结合示例程序叙述。
- Spring框架系列(一)-整体架构
- Spring 框架学习(一):设计理念、整体架构
- spring框架整体架构
- 【Spring从入门到精通】(一)Spring框架的整体架构
- spring源码剖析(一)整体 框架
- Spring源码深度解析(一)Spring的整体架构
- Spring源码深度解析(一)Spring的整体架构
- Spring源码深度解析(一)Spring的整体架构
- Spring源码深度解析(一)Spring的整体架构
- jQuery-1.9.1源码分析系列(一)整体架构
- Spring源码深度解析:Spring入门篇(一)之 Spring整体架构
- UI框架系统剖析系列3(系统整体架构分析)
- Spring源码(一)-Spring整体架构和环境搭建
- jQuery-1.9.1源码分析系列(一)整体架构续
- Spring 整体架构
- Spring整体架构
- Spring整体架构
- spring 整体架构
- Android最流行框架MVP,Dagger2,RxJava
- python 字典操作
- 远程答题系统有哪些?远程答题系统如何使用
- Error parsing D:\sdkforas\android-sdk-windows\system-images\android-24\android-wear\x86\devices.xml
- contianer_of(ptr,type,member)宏解析
- Spring框架系列(一)-整体架构
- iOS转义字符(去除字符窜里的特殊符号)
- 感知器 机器学习算法
- android手机通过蓝牙连接佳博打印机
- Git使用及团队合作
- 【如何正确使用const,static,extern】|那些人追的干货
- 下载量最高的 100 个 Laravel 扩展包推荐
- [JS]笔记18_AJAX2_iframe元素&AJAX跨域&JSONP跨域
- 欢迎使用CSDN-markdown编辑器