[Spring實戰系列](13)使用註解自動裝配
阿新 • • 發佈:2019-01-06
1. 簡介
從Spring2.5開始,我們就可以使用註解的自動裝配方式裝配Spring Bean的屬性。使用註解自動裝配方式與在XML中使用autowire屬性自動裝配沒有太大區別。那為啥還要研發出這樣一種裝配方式?肯定有它獨特的地方:使用註解自動裝配方式允許更細粒度的自動裝配,我們可以選擇性的標註某一個屬性對其應用自動裝配。2. 啟用註解裝配
Spring容器預設禁用註解裝配。所以,在使用基於註解的自動裝配前,我們需要在Spring配置中啟用它。最簡單的啟用方式是使用Spring的context名稱空間配置的<context:annotation-config>元素。<? xml version="1.0" encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
<context:annotation-config/>元素告訴Spring我們打算使用基於註解的自動裝配。一旦裝配完成,我們就可以對程式碼添加註解,表示Spring應該為屬性,方法和構造器進行自動裝配。
3. 使用@Autowired
@Autowired
public void setSchool(School school){
this.school = school;
}
當我們對setSchool()方法使用@Autowired註解時,我們可以移除用來定義Student的school屬性所對應的<property>元素了。如下面配置檔案中的yoona Bean。<?xml version="1.0" encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<beanid="yoona"class="com.sjf.bean.Student">
<propertyname="name"value="yoona"/>
<propertyname="age"value="24"/>
</bean>
<beanid="xidianSchool"class="com.sjf.bean.School">
<propertyname="name"value="西安電子科技大學"/>
<propertyname="location"value="西安"/>
</bean>
</beans>
執行結果:
name:yoona age:24 school:西安電子科技大學[西安] |
使用了@Autowired註解時,Spring就會嘗試對該方法執行byType自動裝配。 |
使用@Autowired註解不只可以使用它標註setter方法,還可以標註需要自動裝配Bean引用的任意方法。甚至是構造器,@Autowired註解表示當建立Bean時,即使Spring XML檔案中沒有使用<constructor-arg>元素配置Bean,該構造器也需要進行自動裝配。Spring會從所有滿足裝配條件的構造器中選擇入參最多的那個構造器。還可以標註屬性,並可以刪除setter方法。 |
@Autowired
publicvoid setSchool(School school){
this.school = school;
}
(2)使用@Autowired註解標註屬性(不受限於private關鍵字):
@Autowired
privateSchool school;
(3)使用@Autowired註解標註任意方法:@Autowired
publicvoid assemblySchool(School school){
this.school = school;
}
(4)使用@Autowired註解標註構造器:@Autowired
publicStudent(School school){
this.school = school;
}
侷限性(同於XML方式):
應用中必須只能有一個Bean適合裝配到@Autowired註解所標註的屬性或者引數中。如果沒有匹配的Bean,或者存在多個匹配的Bean,@Autowired註解就會遇到一些麻煩。 |
3.1 沒有匹配的Bean
如果沒有匹配的Bean,@Autowired註解就會失敗,丟擲NoSuchBeanDefinitionException異常。Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.sjf.bean.School] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {} at org.springframework.beans.factory.support.DefaultListableBeanFactory. raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1373) at org.springframework.beans.factory.support.DefaultListableBeanFactory. doResolveDependency(DefaultListableBeanFactory.java:1119) at org.springframework.beans.factory.support.DefaultListableBeanFactory. resolveDependency(DefaultListableBeanFactory.java:1014) at org.springframework.beans.factory.annotation. AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:618) ... 15 more |
@Autowired(required =false)
publicvoid setSchool(School school){
this.school = school;
}
在這裡,Spring將嘗試裝配school屬性,但是如果沒有查詢到與之匹配的型別為School的Bean,不會丟擲任何異常,並且Student Bean的school屬性會設定為null。
注意點:
required屬性可以用於@Autowired註解所使用的任意地方。但是當使用構造器裝配時,只有一個構造器可以將@Autowired的required屬性設定true。其他使用@Autowired註解所標註的構造器只能將required屬性設定為false。 |
3.2 多個匹配的Bean
另一個問題是可能會有足夠多的(至少2個)都滿足裝配條件,並且都可以被裝配到屬性或引數中。假如,我們有兩個Bean是School型別的,滿足裝配條件。這種情況下,@Autowired註解沒有辦法選擇哪一個Bean才是它需要的,會丟擲NoUniqueBeanDefinitionException異常。<?xml version="1.0" encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<beanid="yoona"class="com.sjf.bean.Student">
<propertyname="name"value="yoona"/>
<propertyname="age"value="24"/>
</bean>
<beanid="xidianSchool"class="com.sjf.bean.School">
<propertyname="name"value="西安電子科技大學"/>
<propertyname="location"value="西安"/>
</bean>
<beanid="shandaSchool"class="com.sjf.bean.School">
<propertyname="name"value="山東大學"/>
<propertyname="location"value="山東"/>
</bean>
</beans>
丟擲異常:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.sjf.bean.School] is defined: expected single matching bean but found 2: xidianSchool,shandaSchool at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1126) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement. inject(AutowiredAnnotationBeanPostProcessor.java:618) ... 15 more |
@Autowired
@Qualifier("shandaSchool")
publicvoid setSchool(School school){
this.school = school;
}
這樣,我們就使用@Qualifier註解嘗試注入ID為"shandaSchool"的Bean。表面上看,把@Autowired的byType自動裝配轉換為顯示的byName裝配。實際只是使用@Qualifier註解縮小了自動裝配挑選候選Bean的範圍。上例中通過指定Bean 的ID把選擇範圍縮小到只剩一個Bean。
除了通過Bean的ID縮小選擇範圍,還可以通過在Bean上直接使用qualifier來縮小範圍。
<?xml version="1.0" encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<beanid="yoona"class="com.sjf.bean.Student">
<propertyname="name"value="yoona"/>
<propertyname="age"value="24"/>
</bean>
<beanid="xidianSchool"class="com.sjf.bean.School">
<propertyname="name"value="西安電子科技大學"/>
<propertyname="location"value="西安"/>
<qualifiervalue="ShanXi"/>
</bean>
<beanid="shandaSchool"class="com.sjf.bean.School">
<propertyname="name"value="山東大學"/>
<propertyname="location"value="山東"/>
<qualifiervalue="ShanDong"/>
</bean>