在應用中,我們常常使用<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[email protected]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容器初始化完畢了......
[email protected]
byType:
隻需要将bean改為如下:
<bean id="autowireTest1" class="com.test.spring.AutowireTest1" autowire="byType">
測試結果:
》》》Spring ApplicationContext容器開始初始化了......
2017-03-19 22:53:54
INFO:ClassPathXmlApplicationContext-Refreshing
org[email protected]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容器初始化完畢了......
[email protected]
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[email protected]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容器初始化完畢了......
[email protected]
總結:
自動裝配的好處:
自動裝配可以有效減少bean标簽的<constructor-arg/>或<property/>元素的使用
自動裝配的局限性和不利條件:
1.顯示的依賴注入<constructor-arg/>或<property/>會重寫自動裝配。不能自動裝配基本資料類型、字元串、數組等,這是自動裝配設計的局限性。
2.自動裝配不如顯示依賴注入精确。如果有可能盡量使用顯示依賴注入。