詳解依賴注入與自動裝配

在我面試的時候,常會問面試者一個問題,就是依賴注入有幾種方式,發現面試者的回答五花八門,有回答兩種的,也有回答三種的,四種的。其實正確的答案是兩種:構造器注入和setter注入。
提到依賴注入,就不能不說裝配。有些初學者老是會把這兩個概念搞混,這個博文就是來跟你們討論這兩個概念以及其中詳細的原理。
依賴注入的本質就是裝配,裝配是依賴注入的具體行爲。這就是二者的關係。例如:
<bean id="hello" class="com.maven.Hello"><constructor-arg value="hello" /></bean>這是使用構造器注入來裝配bean。
<bean id="hello" class="com.maven.Hello" p:hello="hello" />這是使用setter注入,p是spring的名稱空間,能夠用來代替<property>標籤。
以上就是兩種依賴注入方式。上面的注入只是基本類型的注入。下面介紹一下經常使用的注入配置:
1.構造器注入對象屬性
<bean id="text" class="com.maven.Text" />
<bean id="hello" class="com.maven.Hello"><constructor-arg ref="text" /></bean>
2. 屬性注入對象屬性
<bean id="hello" class="com.maven.Hello"><property name="text" ref="text" /></bean>
3. 屬性爲List類型或數組類型屬性注入
<bean id="hello" class="com.maven.Hello">
<property name="persons">
<list>
<ref bean="zhangsan" />
<ref bean="zhangsan" />
</list>
</property>
</bean>
list元素的成員也能夠是<value>,<bean>,<null />,其中<bean>是用來裝配匿名bean的,<null />是用來裝配null值的。匿名bean會在下面介紹。
4.屬性爲set類型的屬性注入
set類型與list類型注入是同樣的,只是標籤改爲<set>就能夠了。而且裏面的元素是不能重複的。
5. 屬性爲map類型的屬性注入
<bean id="hello" class="com.maven.Hello">
<property name="article">
<map>
<entry key="title" value-ref="text" />
<entry key="title" value-ref="text" />
</map>
</property>
</bean>
map類型的鍵和值能夠是任何類型,key-ref用來引用鍵是bean的,value-ref用來引用值是bean的
6. 屬性爲Properties類型的屬性注入
<bean id="hello" class="com.maven.Hello">
<property name="article">
<props>
<prop key="title">I LOVE YOU</prop>
<prop key="title">I HATE YOU</prop>
</props>
</property>
</bean>
Properties類型的元素爲props,每個鍵值標籤是prop,注意要與property標籤進行區分。並且Properties類型的鍵和值必須都是String類型的。而且值是用<prop>標籤內容表示的,而不是用value屬性。
最後說一下匿名bean,這個比較少用。匿名bean跟匿名內部類是同樣的,可是匿名bean不須要實現接口,而且也只能用一次,因此<bean>標籤中不用寫id屬性。例如咱們用匿名bean來做爲屬性注入時:
<property name="text"><bean class="com.maven.Text" /></property>。匿名bean沒有id屬性,由於匿名bean只能被使用一次,加上id屬性沒有意義。
好了,說到這裏,你們能夠看到用xml裝配bean是一件很繁瑣的事情,並且咱們還要找到對應類型的bean才能裝配。
首先,肯定一下裝配的概念。《spring實戰》中給裝配下了一個定義:建立應用對象之間協做關係的行爲稱爲裝配。也就是說當一個對象的屬性是另外一個對象時,實例化時,須要爲這個對象屬性進行實例化。這就是裝配。若是一個對象只經過接口來代表依賴關係,那麼這種依賴就可以在對象自己絕不知情的狀況下,用不一樣的具體實現進行切換。可是這樣會存在一個問題,在傳統的依賴注入配置中,咱們必需要明確要給屬性裝配哪個bean的引用,一旦bean不少,就很差維護了。基於這樣的場景,spring使用註解來進行自動裝配,解決這個問題。自動裝配就是開發人員沒必要知道具體要裝配哪一個bean的引用,這個識別的工做會由spring來完成。與自動裝配配合的還有「自動檢測」,這 個動做會自動識別哪些類須要被配置成bean,進而來進行裝配。這樣咱們就明白了,自動裝配是爲了將依賴注入「自動化」的一個簡化配置的操做。
裝配分爲四種:byName, byType, constructor, autodetect。byName就是會將與屬性的名字同樣的bean進行裝配。byType就是將同屬性同樣類型的bean進行裝配。constructor就是經過構造器來將類型與參數相同的bean進行裝配。autodetect是constructor與byType的組合,會先進行constructor,若是不成功,再進行byType。具體選擇哪種裝配方式,須要配置<bean>標籤的autowire屬性,若是沒有配置,默認是byName類型,就是會根據屬性的名字來進行自動裝配。上面最經常使用的仍是byName和byType。自動裝配時,裝配的bean必須是惟一與屬性進行吻合的,不能多也不能少,有且只有一個能夠進行裝配的bean,才能自動裝配成功。不然會拋出異常。若是要統一全部bean的自動裝配類型,能夠在<beans>標籤中配置default-autowire屬性。固然若是配置了autowire屬性,咱們依然能夠手動裝配屬性,手動裝配會覆蓋自動裝配。
以上是經過xml配置的方式實現自動裝配的,spring2.5以後提供了註解方式的自動裝配。可是要使用這些註解,須要在配置文件中配置<context:annotation-config />。只有加上這一配置,纔可使用註解進行自動裝配,默認狀況下基於註解的裝配是被禁用的。
經常使用的自動裝配註解有如下幾種:@Autowired,@Resource,@Inject,@Qualifier,@Named。@Autowired註解是byType類型的,這個註解能夠用在屬性上面,setter方面上面以及構造器上面。使用這個註解時,就不須要在類中爲屬性添加setter方法了。可是這個屬性是強制性的,也就是說必須得裝配上,若是沒有找到合適的bean可以裝配上,就會拋出異常。這時可使用required=false來容許能夠不被裝配上,默認值爲true。當required=true時,@Autowired要求必須裝配,可是在沒有bean能裝配上時,就會拋出異常:NoSuchBeanDefinitionException,若是required=false時,則不會拋出異常。另外一種狀況是同時有多個bean是一個類型的,也會拋出這個異常。此時須要進一步明確要裝配哪個Bean,這時能夠組合使用@Qualifier註解,值爲Bean的名字便可。@Qualifier註解使用byName進行裝配,這樣能夠在多個類型同樣的bean中,明確使用哪個名字的bean來進行裝配。@Qualifier註解起到了縮小自動裝配候選bean的範圍的做用。注意:@Autowired註解是spring提供的,因此會依賴spring的包。還有一個byType的註解@Inject,與@Autowired註解做用同樣,也是byType類型,並且是java ee提供的,徹底能夠代替@Autowired註解,可是@Inject必須是強制裝配的,沒有required屬性,也就是不能爲null,若是不存在匹配的bean,會拋出異常。@Autowired與@Qualifier能夠組合使用,@Inject也有一個組合的註解,就是@Named註解,與@Qualifier做用同樣,也是byName,可是不是spring的,是java ee標準的。這樣就出現了兩套自動裝配的註解組合,@Autowired與@Qualifier是spring提供的,@Inject與@Named是java ee的。可是@Qualifier註解在java ee中也有同樣,做用與spring的@Qualifier註解如出一轍,只是所在的包不同。不過建議你們使用spring的。最後還有一個@Resouce註解, 這個註解也是java ee的,也是byName類型的,原理同@Qualifier和@Named是同樣的。
最後說一說,自動檢測配置,也是springmvc中最牛的一項功能。只要一個配置<context:component-scan base-package="">,base-package屬性指定要自動檢測掃描的包。
該配置會自動掃描指定的包及其子包下面被構造型註解標註的類,並將這些類註冊爲spring bean,這樣就不用在配置文件一個一個地配置成bean標籤。構造型註解包括:@Controller,@Components,@Service,@Repository和使用@Component標註的自定義註解。生成的bean的ID默認爲類的非限定名,也就是把類的名字的首字母換成小寫。能夠在這些註解的值中寫名bean id的值,如@Controller("helloworld")。若是你想細化包被掃描的範圍,可使用<context:include-filter>和<context:exclude-filter>。具體使用方法這裏再也不詳說。注意,沒有被掃描到的類是不能註冊爲bean,也就不能被用來裝配其餘類。因此這個配置的base-package的範圍很是重要。html

 

 本文選自西安樓鳳java

相關文章
相關標籤/搜索