1.spring特性
一提到spring,想到最多的就是IOC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程),这两个特性不仅让spring框架风靡全球,更是改变了整个行业,所有java开发工程师甚至其他工程师,都开始直接或间接地学习并使用spring的这两大特性,高内聚和低耦合,一切资源变得合理、简单,这不仅是spring框架所追求的的目标,更是面向对象编程甚至整个行业所追求的至高目标。
1).控制反转
a).概念
控制反转,这不是一个技术,而是一种编程思想。究其字面意思,将控制进行了反转,那么我们就有几个问题了:一,控制的啥;二,要是反转的话,之前是谁控制的;三,反转给了谁;四,到底带来了什么变化。
对于第一个问题,控制的是外部资源的获取,包括对象的创建、文件的读取等等。
对于第二个问题,与反转相对的正转到底是咋回事儿,也就是反转之前是谁控制的,我们先举个例子。
public Class A{
public void a(){
System.out.println("output letter a!");
}
}
public Class B{
A aTest= new A();
public void b(){
System.out.println("gonna use function a()!");
aTest.a();
}
}
上面的代码中有两个类,A和B,类A中有个方法a,用来输出一句话,类B中有个方法b,用来调用方法a。如果没有IOC的思想,那么实现起来就像上面的代码一样,我们需要在类B中首先实例化一个A,就是使用new创建一个类A的对象aTest,然后再在方法b中调用aTest.a()来实现对方法a的使用。可以看出,在这个例子中,对象aTest的创建是由类B控制的,在创建了对象的同时,类B就持有了类A的引用,也就是类A的对象成为了类B的成员变量,二者就产生了关联关系,而这种关联关系使得两个类之间的耦合度大大增加,并且类A的实例和类B的生命周期是相同的,当类B被销毁后,类A的实例也就不复存在了。如果我们想再使用方法a,就必须再重新实例化一个A的对象进行调用。这也就是所谓的正转(相对于IOC中的反转来说),这也同时回答了第二个问题,之前是由应用程序自己控制对象的创建的。
对于第三个问题,spring框架实现了一个IOC容器,通过该容器实现了控制反转,也就是说,将对象创建的控制权反转给了IOC容器,应用程序不再控制对象的创建,而是只关心对象的使用。还是上面的例子,为了将控制权交给IOC容器,我们需要进行三个步骤的操作:1.首先,建立类A,其实就是一个bean;2.其次,将类A注册到配置文件中,告诉IOC容器我把类A交给你控制了;最后,建立类B,然后通过IOC容器调用类A的a方法。代码如下:
/**
* 首先,建立类A作为IOC容器中的一个bean
*/
public class A {
public void a() {
System.out.println("output letter a!");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 其次,将类A注册到配置文件中,告诉IOC容器我把类A交给你控制了 -->
<bean id="A" class="springDemo.bean.A">
</bean>
</beans>
/**
* 最后,建立类B,然后通过IOC容器调用类A的a方法
*
*/
public class B{
public static void b() {
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("spring-Config.xml"));//告诉IOC容器配置文件是哪个
A aTest= (A) bf.getBean("A");//IOC容器根据配置文件选择类A并为其创建实例,然后让b方法调用a方法
System.out.println("gonna use function a()!");
aTest.a();
}
对于第四个问题,到底变了什么。我们从代码里可以看到,类B在调用方法a的时候,再也不用对类A进行实例化了,只需要让IOC容器去给它所需要的bean就可以了,而那些对象创建等繁杂的工作都交给了IOC容器去执行;同时,类A的对象的生命周期也是由IOC容器进行管理,与类B已经不相干了。也就是说,当类B销毁之后,类A不一定销毁,如果又出现了一个类C也需要调用a方法,只需要再告诉IOC容器去给它提供就可以了。我们可以得出,IOC容器实现了解耦,将所有的对象进行统一管理,降低了我们编码的复杂性,同时也提高了代码的鲁棒性、复用性和可扩展性。
b).依赖注入和依赖查找
为了实现控制反转,我们可以选择两种方式,一种是依赖查找(Dependency Lookup,DL),一种是依赖注入(Dependency Injection,DI)。二者的根本区别在于对于依赖,对象是主动寻找还是被动接受。依赖查找是对象自己去寻找自己所需要的依赖,例如上文中我们举的类A和类B的例子,类B的方法b需要自己告诉IOC容器它需要哪个bean,让容器给它。而对于依赖注入,则是当这个对象生成的时候,IOC容器将依赖作为属性自动绑定在bean中。spring实现依赖注入主要有三种方式,set方法注入、构造器注入和注解注入。还是上文的例子,这回加一个工具类C,类C依赖于类A,类C有一个方法c,类A的方法a调用方法c。为了实现这个目的,我们需要让类A依赖于类C。
C.class
public class C {
public void c() {
System.out.println("output letter C!");
}
}
set方法注入:
A.class
public class A {
private C cTest;//被注入的对象C
//对象C的set方法
public void setC(C c) {
this.cTest=c;
}
public void a() {
System.out.println("output letter a!");
cTest.c();
}
}
spring-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<bean id="A" class="springDemo.bean.A">
<!-- 将被注入的依赖C作为A的属性写入配置文件中 -->
<property name="C" ref="C"></property>
</bean>
<bean id="C" class="springDemo.bean.C"></bean>
</beans>
构造器注入:
A.class
public class A {
private C cTest;
public A(C c){
this.cTest=c;
}
public void a() {
System.out.println("output letter a!");
cTest.c();
}
}
spring-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<bean id="A" class="springDemo.bean.A">
<constructor-arg ref="C"></constructor-arg>
</bean>
<bean id="C" class="springDemo.bean.C"></bean>
</beans>
注解注入:
spring-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:annotation-config/>
<bean id="A" class="springDemo.bean.A"/>
<bean id="C" class="springDemo.bean.C"/>
</beans>
A.class
@Component
public class A {
@Autowired
C cTest;
public void a() {
System.out.println("output letter a!");
cTest.c();
}
}
从上述代码中,我们可以体会到三种注入方式的区别和联系,通过配置文件告诉IOC容器我们需要注入的依赖是什么,然后再需要注入的地方写好对应的成员变量等,为要注入的依赖提供一个注入的切点。我们也可以看到依赖注入和依赖查找的显著区别,依赖查找是主动向IOC容器进行查找所需要的依赖,而依赖注入则是随着对象的创建,动态初始化依赖并注入到相应对象中,这是一个被动的过程。
2).面向切面编程
与IOC相应的spring的第二大特性AOP,即面向切面编程,它是面向对象编程的一个补充。由于接触的较少,目前为止我只能从理论的角度进行说明,随着接下来的学习,将对AOP的实现机制进行更为深入的理解。面向对象编程实现了业务模块的分离,是对业务横向的解剖,但是如果当我们的几个模块都需要同一个模块工具的时候,我们需要将每一个模块进行重复性的修改,这无疑为开发带来了不便。面向切面编程应运而生。AOP能够让我们在需要的时候,同时为多个模块增加相同的功能,就像对一整个切面进行了修改。笼统的说,AOP能够在不同的时间点,在不同的位置,插入指定方法。目前对于AOP的理解太浅显,接下来还需要在学习工作中重点关注和总结。
2.spring整体架构
书中介绍,spring框架可以分为5个模块,分别是
- Data Access/Intergration
- web
- CoreContainer
- Test
- AOP
1).Data Access/Intergration(数据交互模块)
- JDBC模块提供了一个JDBC抽象层
- ORM模块提供了对象-关系映射API
- OXM模块提供了对象-XML映射的抽象层
- JMS模块包含制造和消费消息的实现
- Transaction则提供了事务管理1).Data Access/Intergration(数据交互模块)
2).Web(Web上下文模块)
- web模块提供了面向web的集成特性
- servlet模块包含spring mvc的实现
- portlet模块提供了用于portlet环境和web-servlet的mvc实现
3).CoreContainer(核心容器模块)
- Beans模块包含spring框架的IOC实现、对bean的创建管理等所有的类
- Core模块包含了spring框架的通用工具类
- Context模块包含了spring的上下文环境
- Expression Language模块提供了spring的表达式语言处理
4).Test(测试模块)
提供了对spring组件进行测试的相关工具
5).AOP(面向切面编程模块)
- AOP模块提供了spring对面向切面编程的实现
- Aspects模块提供了对AspectJ的支持
- Instrumentation模块提供了一些类级的支持,包括类加载器等,该模块主要用于服务器