1.Spring的核心机制
依赖注入:相当于控制反转,spring中创建被调用者的工作不再由调用者完成,称为控制反转,创建被调用者实例的工作由spring容器完成,然后注入调用者,称为依赖注入。
1.1设值注入,依赖注入
1.1.1设值注入
需要setter方法
this.axe=axe;
}
Xml文件里
<property>
<ref local=”steelAxe” />
</property>
</bean>
<bean id=”steelAxe” class=”sheZhiZhuRu.SteelAxe”>
1.1.2 构造注入
构造注入需要带参数的构造器。
this.axe=axe;
}
Xml文件里
<constructor-arg>
<ref bean=”steelAxe” />
</constructor-arg>
</bean>
<bean id=”steelAxe” class=”sheZhiZhuRu.SteelAxe” />
1.1.3两者比较
设置注入优点:
² 与传统的javabean的写法更相似,开发人员容易了解接受。通过setter方法设置依赖关系显得更加直观自然。
² 对于复杂的依赖关系如果采用构造注入会导致构造器过于臃肿,spring创建bean实例时,需要同时实例化其依赖的全部实例,导致性能下降。
² 多参数的构造器过于笨重
构造注入优点
² 可以在构造器中决定依赖关系的注入顺序,优先依赖的优先注入。
² 对于依赖关系无需变化的bean,构造注入更有用处,所以的依赖关系都在构造器中设定,无需担心后续的代码对依赖关系的破坏
² 只有组件的创建者才能改变组件的依赖关系,对于组件调用者,依赖关系完全透明。
建议以设置注入为主,构造注入为辅,对于依赖关系无需变化的注入,尽量采用构造注入,对于其他的,采用设置注入。
Spring中的bean和beanFactory
2.1 BeanFactory接口
BeanFactory为bean工厂,用于配置、创建、管理bean的容器,也称为spring上下文。Bean与bean之间的依赖关系,也由BeanFactory负责维护。
BeanFactory通常对应org.springframework.beans.factory.BeanFactory接口。该接口为spring容器的根接口,spring中的任何容器,都直接或间接的实现该接口,该接口的四种基本方法:
² public Boolean containsBean(String
name):判断spring容器是否包含id为name的bean定义
² public Object getBean(String
name):返回容器中id为name的bean
² public Object getBeans(String
name ,Class requiredType):返回容器中id为name,并且类型requiredType的bean.
² Public Class getType(String
name):返回容器中id为name的bean的类型。
BeanFactory的实现方法:通常使用
org.springframework.beans.factory.xml.xmlBeanFactory类,对于J2EE而言,推荐使用ApplicationContext,其实现类
org.springframerwork.context.support.FileSystemXmlApplicationContext.
创建BeanFactory的实例,应该提供XML的配置文件。XML配置文件通常使用Resource对象传入,Resource接口是spring
bean配置资源的抽象,是所有配置资源的根接口。
实例化BeanFactory:
或者采用以下方法:
如果应用中有多个属性配置文件,应采用BeanFactory子接口ApplicationContext来创建BeanFactory实例,ApplicationContext的实现类:
² FileSystemXmlApplicationContext:以指定路径的xml配置文件创建
ApplicationContext
² ClassPathXmlApplicationContext:以classpath路径下的xml配置文件创建
ApplicationContext
如果有多个配置文件需要加载,需采用如下方式:
Spring最简单的配置文件
2011.5.11
Spring的dtd部分:详细规定了spring配置文件里的合法元素,各元素出现的先后顺序,各元素里的合法子元素、合法属性。
2.2context中的bean
配置文件中<beans>元素可以包含bean子元素,每个</bean>定义一个bean,bean的两个属性:
id: bean的id,唯一的标识符。
class:bean的具体实现类,不能为接口。
2.3 bean的基本行为
Bean在spring容器中有两种基本行为:
² singleton:单态,默认为单态,程序每次请求该Id的bean,spring都会返回该bean的共享实例。
² non-singleton或prototype:原型,如果为该行为,程序每次请求该id的bean,spring都会新建bean实例,该行为的bean,BeanFactory角色相当于New的作用,spring容器不会跟踪bean的生命周期行为。通常要求web应用的控制器bean被设置为non-singleton行为,因为,每次httpServletRequest都需要启动新的action.
设置bean的基本行为,通过singleton属性设置,该属性值只有两个值true,false.
如:<bean id=”axe” class=”steelAxe” singleton=”false” />设置为non-singleton,如果不设置,默认为singleton.
2.4 bean与javabean
建议的bean应满足如下原则:
² 每个bean的实现类都应提供无参数的构造器
² 接受构造注入的bean,应提供相应的构造函数
² 接受设置注入的bean,应提供setter方法,不需要提供getter方法
传统javabean与spring中的bean:
² 用处不同:传统javabean更多作为值对象传递参数,spring中bean几乎无所不包,任何组件都可以称为bean
² 写法不同:传统javabean作为值对象,要求每个属性有getter和setter,spring中的bean只需为设值注入的属性提供setter方法
2.5 实例化bean的方法
三种方法:
- 普通依赖注入里的setter(设值注入)或构造注入,相当于new一个bean实例
- BeanFactory调用某个类的静态工厂方法创建bean
- BeanFactory调用实例工厂方法创建bean
2.5.1普通依赖注入里的setter(设值注入)或构造注入,相当于new一个bean实例
步骤:
1. 程序创建BeanFactory实例
2. 调用Dog实例类的默认构造器创建默认实例
3. 根据配置文件确定的依赖关系,先实例化依赖bean,实现注入
4. 返回完整的javaBean实例
完整代码如下:
相应结构:Being,Dog,Cat位于包shiLiHuaBean.Static,主程序位于
shiLiHuaBean.Constructor
接口Being:
package shiLiHuaBean.Static; public interface Being { public void testBeing(); } |
Dog:
package shiLiHuaBean.Static; public class Dog implements Being{ private String msg; public void setMsg(String msg){ this.msg=msg; } public void testBeing(){ // TODO Auto-generated method stub System.out.println(msg+"爱啃骨头"); } }
Cat:
package shiLiHuaBean.Static;
public class Cat implements Being{
private String msg;
//设置注入须实现set方法
public void setMsg(String msg){
this.msg=msg;
}
public void testBeing() {
// TODO Auto-generated method stub
System.out.println(msg+"爱吃鱼");
}
}
主程序:
package shiLiHuaBean.Constructor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.InputStreamResource;
import shiLiHuaBean.Static.Being;
public class SpringTest {
/**
* @param args
* @throws FileNotFoundException
*/
public static void main(String[] args) throws FileNotFoundException {
// TODO Auto-generated method stub
//实例化BeanFacotry
InputStream is=new FileInputStream("conf.spring/shiLiHuaBeanConstructor.xml");
InputStreamResource isr=new InputStreamResource(is);
XmlBeanFactory factory=new XmlBeanFactory(isr);
Being b1=(Being)factory.getBean("dog");
b1.testBeing();
Being b2=(Being)factory.getBean("cat");
b2.testBeing();
}
}
XML配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="dog" class="shiLiHuaBean.Static.Dog">
<property name="msg">
<value>狗,</value>
</property>
</bean>
<bean id="cat" class="shiLiHuaBean.Static.Dog">
<property name="msg">
<value>猫,</value>
</property>
</bean>
</beans>
2.5.2调用某个类的静态工厂方法创建bean
调用某个类的静态工厂方法创建bean,其中,class属性不再是该bean的类,而是调用的工厂类,factory-method属性确定创建bean的方法名。
注意:工厂方法必须是静态的,如果静态工厂方法需要传入参数,使用<constructor-arg></constructor-arg>传入。
程序如下:
静态工厂方法BeingFacotry:
package shiLiHuaBean.Static; import shiLiHuaBean.Static.Dog; import shiLiHuaBean.Static.Cat; public class BeingFactory { /* * 获取bean实例的静态工厂方法 * @param arg决定返回哪个实例 */ public static Being getBeing(String arg){ if(arg.equalsIgnoreCase("dog")){ return new Dog(); } else{ return new Cat(); } } }
主程序:
package shiLiHuaBean.Static; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.InputStreamResource; public class SpringTest { /** * @param args * @throws FileNotFoundException */ public static void main(String[] args) throws FileNotFoundException { // TODO Auto-generated method stub //创建beanFactory的实例 InputStream is=new FileInputStream("conf.spring/shiLiHuaBeanStatic.xml"); InputStreamResource isr=new InputStreamResource(is); XmlBeanFactory factory=new XmlBeanFactory(isr); Being b1=(Being)factory.getBean("dog"); b1.testBeing(); Being b2=(Being)factory.getBean("cat"); b2.testBeing(); } }
XML配置文件:
<?xml version="1.0" encoding="gb2312"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.sprngframework.org/dtd/spring-beans.dtd"> <beans> <!--采用静态工厂方法产生bean实例,此时的class为产生dog的工厂类,而且必须用factory-method指定产生dog的静态方法 --> <bean id="dog" class="shiLiHuaBean.Static.BeingFactory" factory-method="getBeing"> <!-- 如果方法需要传入参数,需要用constructor-arg设定 --> <constructor-arg> <value>dog</value> </constructor-arg> <!-- property用于确定普通接受依赖注入的属性 --> <property name="msg"> <value>狗,</value> </property> </bean> <bean id="cat" class="shiLiHuaBean.Static.BeingFactory" factory-method="getBeing"> <!-- 如果方法需要传入参数,需要用constructor-arg设定 --> <constructor-arg> <value>cat</value> </constructor-arg> <!-- property用于确定普通接受依赖注入的属性 --> <property name="msg"> <value>猫,</value> </property> </bean> </beans>
采用静态工厂方法创建实例必须提供工厂类,工厂类包含产生实例的静态方法。静态工厂方法创建的实例的使用与之前相同,区别仅在于配置文件的改变:
Ø Class属性指定不再是bean的实现类,而是静态工厂类
Ø 必须有factory-method属性,指定产生实例的静态方法
Ø 如果静态方法有参数传入,使用<constructor-arg>传入。
2.5.3调用实例工厂方法创建bean
通过此方法创建bean,此时bean不再有class属性,而是通过factory-bean确定创建实例的工厂类,factory-method确定产生实例的方法,该方法不为静态。
但,工厂需要返回bean实例,即必须配置工厂bean,具体见XML配置文件
工厂代码:
package shiLiHuaBean.Factory; import shiLiHuaBean.Static.Being; import shiLiHuaBean.Static.Dog; import shiLiHuaBean.Static.Cat; public class BeingFactory { //产生实例的方法 public Being getBeing(String arg){ if(arg.equals("dog")){ return new Dog(); } else{ return new Cat(); } } }
主程序:
package shiLiHuaBean.Factory; import shiLiHuaBean.Static.Being; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.InputStreamResource; public class SpringTest { /** * @param args * @throws FileNotFoundException */ public static void main(String[] args) throws FileNotFoundException { // TODO Auto-generated method stub //创建beanFactory的实例 InputStream is=new FileInputStream("conf.spring/shiLiHuaBeanStatic.xml"); InputStreamResource isr=new InputStreamResource(is); XmlBeanFactory factory=new XmlBeanFactory(isr); Being b1=(Being)factory.getBean("dog"); b1.testBeing(); Being b2=(Being)factory.getBean("cat"); b2.testBeing(); } }
XML配置文件:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <!-- 实例工厂方法创建bean,必须配置工厂bean --> <bean id="BeingFactory" class="shiLiHuaBean.Factory.BeingFactory" /> <!-- 实例工厂方法创建bean,需要指定工厂bean的id属性,用factory-bean指定,factory-method用于指定产生bean实例的方法 --> <bean id="dog" factory-bean="BeingFactory" factory-method="getBeing"> <!-- constructor-arg用于指定方法需要传入的参数 --> <constructor-arg> <value>dog</value> </constructor-arg> <!-- property属性用于指定普通依赖注入的属性 --> <property name="msg"> <value>狗,</value> </property> </bean> <bean id="cat" factory-bean="BeingFactory" factory-method="getBeing"> <constructor-arg> <value>cat</value> </constructor-arg> <property name="msg"> <value>猫,</value> </property> </bean> </beans>
调用实例工厂方法创建bean,与调用静态方法创建bean的用法相似,
区别如下:
- 调用实例工厂方法创建bean,必须将实例工厂配置成bean实例,而静态工厂方法创建bean,无需配置工厂bean
- 调用实例工厂方法创建bean,必须使用factory-bean指定工厂bean,而静态工厂方法创建bean,只需使用class指定静态工厂类
相同之处:
- 都需用factory-method指定产生bean的工厂方法
- 工厂方法如果需要参数,运用<constructor-arg>传入
- 其他依赖注入属性,都使用<property>元素确定参数值
2.6 bean特性的深入
2.6.1 bean的高级属性、合作者
Bean里的依赖通常表现为如下两种方式:
- 通过property属性指定
- 通过constructor-arg属性指定
Spring 在实例化beanfactory 时,会检验bean的配置,包括:
- Bean引用的合作者指向一个合法bean
- 对于singleton行为,并被设置pre-instantiated的bean,spring在创建beanFactory时,同时实例化bean;实例化bean时,也会将它所依赖的bean一起实例化
BeanFactory与ApplicationContext实例化容器中bean的时机不同:前者等到程序需要时才创建,后者在加载ApplicationContext时会自动实例化容器中的全部bean。前者的机制可能会导致配置错误发现的延迟,会给系统带来不确定的危险。而ApplicationContext则默认预实例化singleton-bean。后者比前者预实例化过程时间和内存开销大,但可以在ApplicationContext创建时候找出配置错误。
当然,可以通过设置singleton bean的lazy-load属性为true,可以改变ApplicationContext的默认行为。Bean不会跟随ApplicationContext实例化,Bean依赖通常可以接受如下元素指定值
- value
- ref
- bean
- list, set,map,props
2.6.1.1 value元素
Value元素用于确定字符串参数,参数可以通过PropertyEditors将string转换为所需的参数类型。基本数据类型可以正常转换。
ExampleBean.java
package valueProperty; public class ExampleBean { private int interProperty; private double doubleProperty; public ExampleBean(){ } public int getInterProperty() { return interProperty; } public void setInterProperty(int interProperty) { this.interProperty = interProperty; } public double getDoubleProperty() { return doubleProperty; } public void setDoubleProperty(double doubleProperty) { this.doubleProperty = doubleProperty; } public void test(){ System.out.println(interProperty); System.out.println(doubleProperty); } }
主程序springtest.java
package valueProperty; import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; public class SpringTest { public static void main(String[] args){ ApplicationContext ctx = new FileSystemXmlApplicationContext("conf.spring/valueProperty.xml"); ExampleBean eb=(ExampleBean) ctx.getBean("exampleBean"); eb.test(); } }
配置文件valueProperty.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="exampleBean" class="valueProperty.ExampleBean"> <property name="interProperty"> <value>1</value> </property> <property name="doubleProperty"> <value>2.3</value> </property> </bean> </beans>
执行结果:
1
2.3
Value元素注意用于传入字符串参数,基本数据类型。也可以传入合作者bean,但不推荐使用value.value元素的值可以指定为空,指定空属性通过<null/>元素。
<bean class=”ExampleBean”> <property name=”email”> <value></value> </property> </bean>
与
<bean class=”ExampleBean”> <property name=”email”> <null/> </property> </bean>
2.6.1.2 ref元素
ref:用于指定属性值为spring容器中的其他bean,推荐采用ref元素指定而不是value元素
<bean id=”steelAxe” class=”SteelAxe”> <bean id=”chinese” class=”Chinese”> <property name=”axe”> <ref local=”stellAxe” /> </property> </bean> </bean>
与下面的配置文件效果一样
<bean id=”steelAxe” class=”SteelAxe”> <bean id=”chinese” class=”Chinese”> <property name=”axe”> <value>steelAxe</value> </property> </bean> </bean>
第一种比第二种更好的原因:使用ref标记,可以让spring在部署时验证依赖的bean是否真正存在,第二种,steelAxe属性值仅在创建bean实例时验证,会导致错误的延迟,而且还有额外的类型转换开销,因此,合作者bean属性的传入,推荐采用ref指定。Ref通常有两个属性:
Ø bean: 用于确定不再同一个配置文件中的bean
Ø local:用于确定在同一个XML配置文件中的其他bean,并且local属性只能是其它bean的id属性
ref是local的更严格,并能防止出错的形式,Local则是bean更严格,并能防止出场的形式。
2.6.1.3 bean元素
Bean元素用于定义嵌套bean,而不是在spring中已经存在的bean.嵌套bean只对外部bean有效,没有id属性,不能被spring容器访问,提供了程序内聚性
<bean id=”Chinese” class=”Chinese”> <property name=”axe”> <bean class=”SteelAxe” /> </property> </bean>
2.6.1.4 list.set.map.props元素
list,set,map,props元素分别用于设置List,Set.,Map和Properties的属性值,分别用来为bean传入集合值,代码如下:
Axe接口
package beanYuanSu; public interface Axe { }
StoneAxe.java
package beanYuanSu; public class StoneAxe { public StoneAxe(){ } public String chop(){ return "Use stoneAxe "; } }
Person接口
package beanYuanSu; public interface Person { public void test(); }
Chinese.java
package beanYuanSu; import java.util.List; //一定要是java.util.List; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Properties; import java.util.Set; public class Chinese implements Person{ //系列集合属性 private List schools=new ArrayList(); private Map score=(Map)new HashMap(); private Properties health=new Properties(); private Set axes=(Set)new HashSet(); public Chinese() { System.out.println("Sprint实例化主调bean,Chinese实例...."); } public void setSchools(List schools) { this.schools = (java.util.List) schools; } public void setScore(Map score) { this.score = score; } public void setAxes(Set axes) { this.axes = axes; } public void setHealth(Properties health){ this.health=health; } public void test(){ System.out.println(schools); System.out.println(score); System.out.println(health); System.out.println(axes); } }
主程序
SpringTest.java
package beanYuanSu; import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; public class SpringTest { public static void main(String[] args){ ApplicationContext ctx=new FileSystemXmlApplicationContext("conf.spring/beanYuanSu.xml"); Person p=(Person)ctx.getBean("Chinese"); p.test(); } }
Xml配置文件beanYuanSu.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <!--spring配置文件的根元素 --> <beans> <bean id="stoneAxe" class="beanYuanSu.StoneAxe" /> <!--定义 chinese bean--> <bean id="Chinese" class="beanYuanSu.Chinese"> <!-- 定义list属性,使用List元素 --> <property name="schools"> <!-- list 元素里使用value确定系列值--> <list> <value>小学</value> <value>中学</value> <value>大学</value> </list> </property> <!-- 定义Map属性,使用map元素 --> <property name="score"> <map> <!-- map属性必须是key-value对 --> <entry key="数学"> <value>80</value> </entry> <entry key="英语"> <value>90</value> </entry> </map> </property> <!-- 定义properties属性,使用props元素 --> <property name="health"> <props> <!-- props 属性必须是key-value 对 --> <prop key=" 血压">正常</prop> <prop key="身高">175</prop> </props> </property> <property name="axes"> <!-- set属性 --> <set> <value>字符串斧子</value> <bean class="beanYuanSu.StoneAxe"></bean> <ref local="stoneAxe" /> </set> </property> </bean> </beans>
输出结果
|
如上配置文件:set元素可以通过value,bean,ref确定值,map元素entry的值,set元素的值都可以使用如下元素。
Ø value:确定基本数据类型值,或字符串类型值
Ø ref:确定另一个bean为属性值
Ø bean:确定一个嵌套bean为属性值
Ø list,map,set,props:确定集合为属性值
2.6.2 使用depends-on强制初始化bean
如果一个类的初始化块会使用其他bean,而此时spring总是先初始化主调bean,执行初始化时还没有实例化主调bean,被依赖bean还没实例化,使用depends-on可以在初始化主调bean之前强制一个或多个bean初始化。配置文件
<!—配置beanOne,该bean需要实例化之前,使用manager bean ,使用depends-on强制manager bean在初始化beanOne之前实例化--> <bean id=”beanOne” class=”BeanOne” depends-on=”manager”> <property name=”manager”> <ref local=”manager” /> </property> </bean> <bean id=”manager” class=”ManagerBean” />
2.6.3 自动装配
即spring可以自动装配bean与bean之间的关系,无需使用ref显式指定依赖bean。由beanFactory检查XML配置文件内容,为主调bean注入依赖关系。它可以具体 指定到每个bean,可让某个bean使用自动装配,某些不使用。
可以减少配置文件的工作量,但降低了依赖关系的透明性和清晰性。通过autowire属性可以接受如下5种值。
- no: 不使用自动装配。Bean依赖必须通过ref元素定义。这是默认的配置,在较大的部署环境中不鼓励改变这个配置,指定合作者能够得到更多的控制和清晰性。
- byName:根据属性名自动装配。BeanFactory查找容器中全部bean,找出其中ID属性与属性名同名的bean
- byType:根据属性类型自动装配。BeanFactory查找容器中全部bean,如果正好有一个与依赖属性类型相同的bean,自动装配这个属性,如果有多个,抛出异常。如果没有,什么都不会发生,属性不会被设置。如果需要无法自动装配是抛出异常,设置dependency-check=”object”.
- constructor:与byType类似,区别是用于构造注入的参数,如果beanFactory中,不是恰好有一个bean与构造器参数相同类型,产生致命错误
- autodetect:beanFactory根据bean内部结构,决定使用constructor或byType,如果找到一个默认的构造函数,那么就会应用byType.
2.6.3.1 byName
配置文件
<beans> <bean id=”chinese” class=”Chinese” autowire=”byName” /> <bean id=”gundog” class=”GunDog”> <property name=”name”> <value>wangwang</value> </property> </bean> </beans>
上面的配置文件,要求Chinese类中有如下方法:
/* 依赖关系必须的setter方法,因为需要通过名字自动装配,因此setter方法名必须是set+bean名。Bean名首字母大写 */ public void setGunDong(Dog dog){ this.dog=dog; }
2.6.3.2 byType
配置文件:
<beans> <bean id=”chinese” class=”Chinese” autowire=”byType” /> <bean id=”gundog” class=”GunDog”> <property name=”name”> <value>wangwang</value> </property> </bean> </beans>
上面的配置文件,要求Chinese类中有如下方法:
/* 依赖关系必须的setter方法,因为需要通过类型自动装配,因此setter方法的参数类型与容器的bean的类型相同,程序中的GunDog实现Dog接口 */ public void setGunDong(Dog dog){ this.dog=dog; }
如果出现以下配置文件
<beans> <bean id=”chinese” class=”Chinese” autowire=”byType” /> <bean id=”gundog” class=”GunDog”> <property name=”name”> <value>wangwang</value> </property> </bean> <bean id=petdog” class=”PetDog”> <property name=”name”> <value>ohoh</value> </property> </bean> </beans>
此时spring无法实现自动装配,容器中有两个类型为Dog的bean,spring无法确定应为chinese注入那个bean。
当一个bean既使用自动装配依赖,又使用ref显式指定依赖,则显式指定依赖覆盖自动装配。
<beans> <bean id=”chinese” class=”Chinese” autowire=”byType” > <property name=”GunDog”>\ <ref local=”GunDog”> </property> </bean> <bean id=”gundog” class=”GunDog”> <property name=”name”> <value>wangwang</value> </property> </bean> <bean id=petdog” class=”PetDog”> <property name=”name”> <value>ohoh</value> </property> </bean> </beans>
此时chinese会被注入GunDog类实例,显式的ref指定依赖覆盖自动装配指定的依赖。
注:对于大型的应用,不鼓励使用自动装配。自动装配减少了配置文件的工作量,但降低了依赖关系的清晰性和透明性,依赖关系的装配依赖于源文件的属性名,导致bean与bean之间的耦合降低到代码层次,不利于高层次解耦。
2.6.4 依赖检查
依赖检查可以保证bean的属性得到正确设置,但某些情况下,并不需要为bean的每个属性都设置值,或者某些属性已经有默认的值,此时采用依赖检查就会出错。
默认不应用依赖检查,通过dependency-check属性设置
Ø none: 不进行依赖检查。没有指定值得bean属性仅仅是没有设值。
Ø simple:对基本类型和集合(除了合作者bean)进行依赖检查
Ø objects:仅对合作者bean进行依赖检查
Ø all: 对所有进行依赖检查,包括合作者bean,基本类型和集合。
Chinese.java
package dependencyCheck; public class Chinese { private String name; private int age=20; private Axe axe; public Axe getAxe() { return axe; } public void setAxe(Axe axe) { this.axe = axe; } public Chinese(){ } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void test(){ System.out.println("name:"+name); System.out.println("age:"+age); axe.chop(); } }
Axe.java
package dependencyCheck; public class Axe { public void chop(){ System.out.println("斧子"); } }
主程序springTest.java
package dependencyCheck; import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; public class SpringTest { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub ApplicationContext ctx=new FileSystemXmlApplicationContext("conf.spring/dependencyCheck.xml"); Chinese c=(Chinese) ctx.getBean("Chinese"); c.test(); } }
配置文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="axe" class="dependencyCheck.Axe" /> <bean id="Chinese" class="dependencyCheck.Chinese" dependency-check="objects"> <property name="name"> <value>ttt</value> </property> <property name="axe"> <ref local="axe" /> </property> </bean> </beans>
此时不会出错,如果改成dependency-check="all",会出错。