1.Spring的核心机制
依赖注入:相当于控制反转,spring中创建被调用者的工作不再由调用者完成,称为控制反转,创建被调用者实例的工作由spring容器完成,然后注入调用者,称为依赖注入。
1.1设值注入,依赖注入
1.1.1设值注入
需要setter方法
Public void setAxe(Axe axe){ this.axe=axe; }
Xml文件里
<bean id=”chinese” class=”sheZhiZhuRu.Chinese”> <property> <ref local=”steelAxe” /> </property> </bean> <bean id=”steelAxe” class=”sheZhiZhuRu.SteelAxe”>
1.1.2 构造注入
构造注入需要带参数的构造器。
Public Chinese(Axe axe){ this.axe=axe; }
Xml文件里
<bean id=”chinese” class=”sheZhiZhuRu.Chinese”> <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:
//以指定路径下bean.xml配置文件作为参数,创建文件输入流 InputStream is=new FileInputStream(“bean.xml”); //以指定的文件输入流is,创建Resource文件 InputStreamResource isr=new InputStreamResource(is); //以Resource对象作为参数,创建BeanFactory实例 XmlBeanFactory factory=new XmlBeanFactory(isr);
或者采用以下方法:
//搜索CLASSPATH路径,以CLASSPATH路径下的bean.xml文件创建对象ClassPathResource res=new ClassPathResource(“bean.xml”);//以Resource对象为参数,创建BeanFactory实例XmlBeanFactory factory=new XmlBeanFactory(res);
如果应用中有多个属性配置文件,应采用BeanFactory子接口ApplicationContext来创建BeanFactory实例,ApplicationContext的实现类:
² FileSystemXmlApplicationContext:以指定路径的xml配置文件创建
ApplicationContext
² ClassPathXmlApplicationContext:以classpath路径下的xml配置文件创建
ApplicationContext
如果有多个配置文件需要加载,需采用如下方式:
//搜索classpath路径,以classpath路径下的application.xml和service.xml文件创建ApplicationContext ClassPathXmlApplicationContext appContext=new ClassPathXmlApplicationContext (new String[]{“application.xml”,”service.xml”}); //子接口,支持强制类型转换 BeanFactory factory=(BeanFactory)appContext; ------------------------------------------------- //指定路径下的application.xml和service.xml文件创建ApplicationContext FileSystemXmlApplicationContext appContext=new FileSystemXmlApplicationContext (new String[]{“application.xml”,”service.xml”}); //子接口,支持强制类型转换 BeanFactory factory=(BeanFactory)appContext;
Spring最简单的配置文件
2011.5.11
<?xml version=”1.0” encoding=”gb2312”> <!—指定spring配置文件的dtd--> <!DOCTYPE beans PUBLIC “-//SPRING//DTD BEAN//EN” “http://www.springframework.org/dtd/spring-beans.dtd”> <beans> </beans>
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:
|
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>
输出结果
[小学, 中学, 大学] {数学=80, 英语=90} {身高=175, 血压=正常} [字符串斧子, beanYuanSu.StoneAxe@7bd9f2, beanYuanSu.StoneAxe@121cc40]
|
如上配置文件: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",会出错。