在应用中,我们常常使用<ref>标签为JavaBean注入它依赖的对象。但是对于一个大型的系统,这个操作将会耗费我们大量的资源,我们不得不花费大量的时间和精力用于创建和维护系统中的<ref>标签。实际上,这种方式也会在另一种形式上增加了应用程序的复杂性,那么如何解决这个问题呢?spring为我们提供了一个自动装配的机制,尽管这种机制不是很完善,但是在应用中结合<ref>标签还是可以大大的减少我们的劳动强度。前面提到过,在定义Bean时,<bean>标签有一个autowire属性,我们可以通过指定它来让容器为受管JavaBean自动注入依赖对象。
<bean>的autowire属性有如下六个取值,他们的说明如下:
1、 No:即不启用自动装配。Autowire默认的值。这种情况下,用户必须自己去通过ref 指明被注入的bean ID
如:<property name="myname" ref="studentName">
<property name="printer" ref="printer">
2、 byName:根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean(找该定bean的bean ID),并将其与属性自动装配。
如: <bean id="userManagerTarget" autowire="byName">
<property name="baseDAO"/> </bean>
这样对于bean userManagerTarget的属性baseDAO,spring就会自动去引用名为baseDAO的bean,也就是上面的声明和下面是等价的。
<bean id="userManagerTarget" autowire="no">
<property name="baseDAO"> <ref local="baseDAO"/>
</property>
</bean>
这里,userManagerTarget类必须提供setter方法如下:
void setBaseDAO(BaseDAO mydao){
this.baseDAO=mydao;
}
3、 byType:通过属性的类型查找JavaBean依赖的对象并为其注入。比如类Computer有个属性printer,类型为Printer,那么,指定其autowire属性为byType后,Spring IoC容器会查找Class定义为Printer的bean,使用Seter方法为其注入。
这里,Computer类必须提供setter方法如下:
void setPrinter(Printer myprinter){
this.printer=myprinter;
}
如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配;如果存在多个该类型bean,那么抛出异常,并指出不能使用byType方式进行自动装配;如果没有找到相匹配的bean,则什么事都不发生,也可以通过设置dependency-check="objects"让Spring抛出异常。
4、 constructor:通byType一样,也是通过类型查找依赖对象。与byType的区别在于它不是使用setter方法注入,而是使用构造器注入。
constructor:与byType方式类似,不同之处在于它应用于构造器参数。如果容器中没有找到与构造器参数类型一致的bean, 那么抛出异常。 reference原文是: This is analogous to byType, but applies to constructor arguments. If there isn't exactly one bean of the constructor argument type in the bean factory, a fatal error is raised.
5、 autodetect:在byType和constructor之间自动的选择注入方式。
6、 default:由上级标签<beans>的default-autowire属性确定。
byName示例:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="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"> <bean id="autowireTest1" class="com.test.spring.AutowireTest1" autowire="byName"> </bean> <bean id="autowireTest2" class="com.test.spring.AutowireTest2"> </bean> </beans>
Java 类:
package com.test.spring; public class AutowireTest1 { private AutowireTest2 autowireTest2; public AutowireTest2 getAutowireTest2() { return autowireTest2; } public void setAutowireTest2(AutowireTest2 autowireTest2) { this.autowireTest2 = autowireTest2; } } ------------------------------------------------------------------------------------------- package com.test.spring; public class AutowireTest2 { }
测试:
package com.test.spring; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class T { ApplicationContext applicationcontext=null; @Before public void before() { System.out.println("》》》Spring ApplicationContext容器开始初始化了......"); applicationcontext= new ClassPathXmlApplicationContext(new String[]{"test1-service.xml"}); System.out.println("》》》Spring ApplicationContext容器初始化完毕了......"); } @Test public void test() { AutowireTest1 autowireTest1= applicationcontext.getBean(AutowireTest1.class); System.out.println(autowireTest1.getAutowireTest2()); } }
测试结果:
》》》Spring ApplicationContext容器开始初始化了......
2017-03-19 22:53:54 INFO:ClassPathXmlApplicationContext-Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@496419dc: startup date [Sun Mar 19 22:53:54 CST 2017]; root of context hierarchy
2017-03-19 22:53:54 INFO:XmlBeanDefinitionReader-Loading XML bean definitions from class path resource [test1-service.xml]
》》》Spring ApplicationContext容器初始化完毕了......
com.test.spring.AutowireTest2@63465272
byType:
只需要将bean改为如下:
<bean id="autowireTest1" class="com.test.spring.AutowireTest1" autowire="byType">
测试结果:
》》》Spring ApplicationContext容器开始初始化了......
2017-03-19 22:53:54
INFO:ClassPathXmlApplicationContext-Refreshing
org.springframework.context.support.ClassPathXmlApplicationContext@496419dc:
startup date [Sun Mar 19 22:53:54 CST 2017]; root of context hierarchy
2017-03-19 22:53:54 INFO:XmlBeanDefinitionReader-Loading XML bean definitions from class path resource [test1-service.xml]
》》》Spring ApplicationContext容器初始化完毕了......
com.test.spring.AutowireTest2@63465272
constructor:
只需要将bean改为如下:
<bean id="autowireTest1" class="com.test.spring.AutowireTest1" autowire="constructor">
对应AutowireTest1类改为:
package com.test.spring; public class AutowireTest1 { private AutowireTest2 autowireTest2; public AutowireTest1(AutowireTest2 autowireTest2) { this.autowireTest2 = autowireTest2; } }
测试结果输出:
》》》Spring ApplicationContext容器开始初始化了......
2017-03-20 09:13:48 INFO:ClassPathXmlApplicationContext-Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@4752dd7b: startup date [Mon Mar 20 09:13:48 CST 2017]; root of context hierarchy
2017-03-20 09:13:48 INFO:XmlBeanDefinitionReader-Loading XML bean definitions from class path resource [test1-service.xml]
》》》Spring ApplicationContext容器初始化完毕了......
com.test.spring.AutowireTest1@43bb703d
总结:
自动装配的好处:
自动装配可以有效减少bean标签的<constructor-arg/>或<property/>元素的使用
自动装配的局限性和不利条件:
1.显示的依赖注入<constructor-arg/>或<property/>会重写自动装配。不能自动装配基本数据类型、字符串、数组等,这是自动装配设计的局限性。
2.自动装配不如显示依赖注入精确。如果有可能尽量使用显示依赖注入。