综述
Spring框架的基本思想就是,通过XML配置来驱动Java代码,这样就可以把原来由Java代码管理的耦合关系,提取到XML配置文件中管理。通过这种方式实现系统中各组件的解耦,有利于系统的维护和升级。
依赖注入
Spring提供了两种注入方式:构造注入和设值注入,构造注入通过<constructor-arg.../>
调用对应含参构造器;设值注入通过<property.../>
调用对应的setter方法。Bean注入的成员变量可以分为四种。
- 普通成员变量。 通过指定property的value属性实现。
<property name="intField" value="1"/>
,<property name="double" value="2.3"/>
- 引用成员变量。通过指定property的ref属性实现
<property name="axe" ref="steelAxe"/>
。也可以通过配置autowrite属性让Spring自动装配Bean的引用成员变量,但在大型应用中自动装配会降低依赖关系的清晰度和透明度。如果被引用的Bean不需要被Spring容器访问,可以考虑使用嵌套Bean。 - 数组和集合变量。通过在
<property></property>
中嵌入对应的数组和集合元素实现注入,其中,数组和list都使用 - 组合成员变量。Spring允许直接为Bean成员变量的属性赋值,
<bean id="exam" class="com.jeff.Exam"><property name="foo.bar.x.y" value="12"/></bean>
相当于执行exam.getFoo().getBar().getX.setY(12)
Spring Bean和Java Bean的区别
- JavaBean一般作为值对象传递参数:Spring Bean几乎无所不包,任何组件都可以当做Bean。
- JavaBean作为传值对象,要求每个属性都提供setter和getter;Spring Bean只需为接受设置注入的属性提供setter即可
- JavaBean作为值对象传递,其生命周期直接由JVM控制;Spring Bean由Spring管理其生命周期。
创建Bean的方法
Spring提供了三种创建Bean的方法:
- 使用构造器创建Bean,如果采用构造注入,Spring通过反射调用对应的构造函数创建Bean;如果采用设值注入,Spring调用默认构造函数创建Bean,通过setter注入参数。
- 使用静态工厂创建Bean,
<bean>
元素中需要指定class——静态工厂类的类名和factory-method——使用的静态方法。如果静态工厂需要参数,通过<constructor-arg>
传入。 - 使用实例工厂方法创建Bean,与静态工厂不同,实例工厂也是一个由Spring管理的Bean。使用实例工厂方法创建Bean时,需要指定factory-bean——工厂Bean的id和factory-method——实例工厂的方法。
Bean的生命周期
Spring容器负责管理singleton作用域的Bean生命周期,包括创建、初始化和销毁等。对于prototype作用域的Bean,Spring只负责创建,创建完成之后就交给客户端代码管理。
Bean依赖注入完成后的行为
Spring提供两种方式在Bean的全部属性设置完成执行特定操作:使用init-method属性和实现InitializingBean接口。如果同时实现这两种方法,inti-method属性指定的方法后执行。
Bean销毁前的行为
Spring也提供了两种方式定制Bean实例销毁前的特定性为:使用destory-method属性和实现DisposableBean接口。如果同时实现这两种方法,destory-method属性指定的方法后执行。
不同作用域Bean之间的协同
如果singleton Bean调用prototype Bean,在不采用协同措施的情况下,singleton Bean每次访问prototype Bean时都只会得到注入时的Bean。prototy Bean的行为会变成singleton Bean的行为。
为了让protot Bean表现正常的行为,可以采用lookup方法注入,Spring通过使用JDK动态代理或者cglib库修改客户端代码。具体方法为:
- 调用者Bean的实现类定义为抽象类,并定义一个抽象方法来获取被依赖的Bean。
- 在调用者<bean…/>元素中添加<lookup-method…/>子元素,指定Spring需要实现的抽象方法。
Spring为抽象方法提供实现之后,这个方法就变成具体的方法,这个类也变成具体类,接下来Spring就可以创建该Bean的实例了。