Spring中,對象無需自己查找或創建與其所關聯的其他對象。相反,容器負責把需要相互協作的對象引用賦予各個對象。例如一個訂單管理組件需要信用卡認證組件,但它無需自己創建信用卡認證組件,訂單管理組件秩序只需表明自己兩手空空,容器就會主動賦予它一個in用卡認證組件。
創建應用對象之間協作關係的行爲通常稱爲裝配(wiring),這也是依賴注入(DI)的本質。
一、Spring配置bean可選方案
在Spring中裝配bean有多種方式,最常見的有三種:
- 在XML中進行顯式配置
- 在java中進行顯式配置
- 隱式的bean發現機制和自動裝配
二、自動化裝配bean
Spring從兩個角度來實現自動化裝配:
- 組件掃描(component scanning):spring會自動發現應用上下文中所創建的bean
- 自動裝配(autowiring):Spring自動滿足bean之間的依賴
組件掃描和自動裝配組合在一起能將顯示配置降低到最少。
1.創建可被發現的bean
@Component標記需要自動裝載的類,@ComponentScan自動掃描bean
2.爲組建掃描的bean命名
Spring應用上下文中所有的bean都會給定一個ID。沒有明確設置ID,Spring會根據類名爲其制定一個ID,即將類名的第一個字母變爲小寫作爲ID。
- 使用@Component 時:如需爲這個bean設置不同的ID,則將期望的ID作爲值傳給@Component註解,例如@Component(“XXX”)
- @Named方式:不用@Component註解,而是使用java依賴注入規範中提供的@Named註解來爲bean設置ID
3.設置組件掃描的基礎包
@ComponentScan可配置基礎掃規則:
- 默認規則:當未爲@ComponentScan配置屬性時,按照默認規則會以配置類所在的包作爲掃描的基礎包。
- 配置單個包規則:@ComponentScan(“com.XXX”)。
- 配置多個掃描包規則:@ComponentScan(basePackages={“com.XXX1”,”com.XXX2”})。
- 配置規則類所在的包:以上配置的basePackages的值是以String類型表示的,但這種方式不安全,如果重構代碼所指定的基礎包可能就會出現錯誤(String無法直接在編譯或idea中直接識別,改了包名後容易忽視配置的規則包),所以提供了另一種方式,將規則配置爲目標規則包中所包含的類或者接口,basePackages屬性被basePackageClasses,便於重構時引用非法,@ComponentScan(basePackageClasses={XXXCls.class,XXX2Cls.class})。
如果所有的bean都是獨立的,彼此間沒有依賴,使用Component和ComponentScan即可完成注入
4.通過爲bean添加註解實現自動裝配
- @Autowired
可以使用到構造器上,還能用在屬性的Setter方法。
如有且只有一個bean匹配依賴需求的話,那麼這個bean將會被裝配進來。
如果沒有匹配的bean,那麼在應用上下文創建的時候,Spring會拋出一個異常爲了避免異常的出現,你可以將@Autowired的required屬性設置爲false:
@Autowired(required=false)
將required屬性設置爲false時,Spring會嘗試執行自動裝配,但是如果沒有匹配的bean的話,Spring將會讓這個bean處於未裝配的狀態。但是,把required屬性設置爲false時,你需要謹慎對待。如果在你的代碼中沒有進行null檢查的話,這個處於未裝配狀態的屬性有可能會出現NullPointerException。
- @Inject
Inject註解來源於Java依賴注入規範,該規範同時還爲我們定義了@Named註解。在自動裝配中,Spring同時支持@Inject和@Autowired。儘管@Inject和@Autowired之間有着一些細微的差別,但是在大多數場景下,它們都是可以互相替換的。
三、通過java代碼配置bean
在很多場景下通過組件掃描和自動裝配實現Spring的自動化配置是更爲推薦的方式,但有時候自動化配置的方案行不通,因此需要明確配置Spring。比如說,你想要將第三方庫中的組件裝配到你的應用中,在這種情況下,是沒有辦法在它的類上添加@Component和@Autowired註解的,因此就不能使用自動化裝配的方案了。必須要採用顯式裝配的方式。
顯示配置相關注解:
- @Configuration
- @Bean
http://blog.csdn.net/L_Sail/article/details/66999814
四、通過XML裝配bean
在裝配bean的時候,有另一種可選方案,即XML配置。
在Spring剛剛出現的時候,XML是描述配置的主要方式。在Spring的名義下,我們創建了無數行XML代碼。在一定程度上,Spring成爲了XML配置的同義詞。
儘管Spring長期以來確實與XML有着關聯,但現在需要明確的是,XML不再是配置Spring的唯一可選方案。Spring現在有了強大的自動化配置和基於Java的配置,XML不應該再是第一選擇了。鑑於已經存在那麼多基於XML的Spring配置,所以理解如何在Spring中使用XML還是很重要的。
XML裝配bean步驟如下:
1.配置規範 :
在使用XML爲Spring裝配前,需要創建一個新的配置規範。在使用javaConfig的時候這意味着要創建一個帶有@Configuration註解的類,而在ML配置中,就意味着要創建一個ML文件,並且要以元素爲跟。
<?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
http://www.springframework.org/schema/context">
<!-- do something -->
</beans>
基本XML配置比同等功能的JavaConfig類複雜,在JavaConfig中秩序@Configuration,而在XML中需要在配置文件的等不聲明多個XML模式的XSD文件來定義配置Spring的XML元素。
用來裝配bean的最基本的XML元素包含在spring-beans模式之中,在上面這個XML文件中,它被定義爲根命名空間。是該模式中的一個元素,它是所有Spring配置文件的根元素。
由於中沒有聲明任何bean,因此這個合法的基礎SpringXML配置暫無用處,需要配置bean來實現。
2.聲明bean:
- 聲明註解
要在基於XML的Spring配置中聲明一個bean,要使用spring-beans模式中的另一個元素,元素類似於JavaConfig中的@Bean註解:
<bean class="sound.sgtPeppers" />
- bean在xml中命名設置
因爲沒有明確給定ID,bean將會根據全限定類名來進行命名,上例中bean的ID是“sound.sgtPeppers#0”,#0是計數的形式,用來區分相同類型的其他bean,如果聲明瞭另一個sgtPeppers,並且沒有明確進行表示,那自動得到的ID將會是“sound.sgtPeppers#1”。
儘管自動化的bean命名方式非常方便,但如果稍後要引用,那自動產生的名字就無用了,因此最好是藉助id屬性,爲每個bean設置一個唯一名字:
<bean class="sound.sgtPeppers" id="compactDis" />
減少繁瑣爲了減少XML中繁瑣的配置,只對那些需要按名字引用的bean(比如,需要將對它的引用注入到另一個bean中)進行明確命名。
- xml中bean的特徵(與JavaConfig比的缺點)
- 不再需要直接在代碼中負責創建bean對應的實例,由容器被動創建
當spring發現xml中bean元素時會調用默認構造器來創建bean。xml配置bean創建非常被動,而JavaConfig常見bean則強大的多,可以以任何方式創建。 - xml配置bean的類型如class等屬性以string的形式設置,無法保證配置有效
以配置class爲例,當修改了類名後,xml中的string屬性並不能在編譯期間檢查到是否合法,可能需要手動檢查後修改(藉助IDE檢查XML的合法性使用能夠感知Spring功能的IDE,如Spring Tool Suite,能夠在很大程度上幫助你確保Spring XML配置的合法性,但任然無法保證能完全檢查到)。
- 不再需要直接在代碼中負責創建bean對應的實例,由容器被動創建
3.藉助構造器注入初始化bean:
配置DI方式:
在spring XML配置中只有一個聲明bean的方式:使用bean標籤。
但是在聲明DI時,會有多種可選的配置方案:constructor-arg標籤元素
使用Spring3.0引入的c-命名空間
兩者區別很大程度在於是否冗長繁瑣。使用constructor-arg元素比使用c-命名空間更加冗長導致XML更難讀,但constructor-args可以配置或設置更多c-命名空間無法實現的功能。constructor-arg初始化beanDI:
XML中若一個bean初始化時與需要同時注入另一個bean,需要使用bean元素分別聲明這些bean,在需要映入其他bean來初始化的bean中通過ID來引用:
<bean id="b1Id" class="xx.xx.B1"/>
<bean id="b2Id" class="x.xx.B2">
<constructor-arg ref="b1Id" />
</bean>
當spring發現這個<bean id="b2Id">
元素時會創建一個B2實例,<constructor-arg>
元素會告知spring要將一個id爲b1Id的bean引用傳遞到b2的構造器中。
- 命名空間c-初始化beanDI:
作爲初始化的替代方案,可以使用Spring的c-命名空間。c-命名空間是在Spring3.0中引入的,他在XML中更爲簡潔的描述構造器參數的方式:
xml頂部聲明其模式:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:c="https://www.springframework.org/schema/c"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
...
</beans>
聲明構造器參數:
<bean id="bean1" class="com.xx.bean1" c:cd-ref="bean2"/>
<bean id="bean1" class="com.xx.bean1" c:_0-ref="bean2"/>
<bean id="bean1" class="com.xx.bean1" c:_-ref="bean2"/>
將字面量注入到構造器中:
(只有一個構造器參數)
<bean id="bean1" class="com.xx.bean1" c:_="hahaha"/>
(多個屬性構造參數)
<bean id ="bean1" class="com.xx.bean1" c:_title="hahaha" c:_name="hahah"/>
<bean id="bean1" class="com.xx.bean1" c:_0="hahah"
c:_1="hahaha"/>
構造器注入字面量:
<bean id="bean1" class="com.xx.bean1">
<constructor-arg value="hahah"/>
<constructor-arg value="hahaha"/>
<constructor-arg><null/></constructor-arg>
</bean>
<bean id="bean1" class="com.xx.bean1">
<constructor-arg value="hahah"/>
<constructor-arg value="hahaha"/>
<list>
<value>11111</value>
<value>22222</value>
...
<list>
</constructor-arg>
</bean>
<bean id="bean1" class="com.xx.bean1">
<constructor-arg value="hahah"/>
<constructor-arg value="hahaha"/>
<list>
<ref bean="bean111"/>
<ref bean="bean111"/>
...
<list>
</constructor-arg>
</bean>
<bean id="bean1" class="com.xx.bean1">
<constructor-arg value="hahah"/>
<constructor-arg value="hahaha"/>
<set>
<value>11111</value>
<value>22222</value>
...
<set>
</constructor-arg>
</bean>
通過對比,constructor-arg比c-命名空間更具優勢,c-目前無法實現裝配集合。
4.設置屬性:
<property>
<bean id="bean1" class="com.xx.bean1">
<property name="bean2" ref="bean2Id" />
<property name="title" value="hahaha"/>
<property name="tracks">
<list>
<value>hahahah</value>
<value>deeedep</value>
...
</list>
</property>
<property>
</property>
</bean>
元素爲屬性的setter方法所提供的功能與元素構造器提供的功能是一樣的。
- p-命名空間:
spring提供了p-命名空間作爲元素的替代方案:
xml頂部聲明:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
...
>
</beans>
裝配屬性:
<bean id="bean1" class="com.xx.bean1" p:bean2-ref="bean2" />
- -util命名空間:
由於p-命名空間無法裝配集合,因此可以使用Spring util-命名空間中的一些功能來簡化BlankDiscbean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
...
<beans>
util-命名空間所提供的功能之一就是元素,它會創建一個列表的bean
...
<util:list id="trackingList">
<value>11111eee</value>
<value>22222kkk</value>
....
</util:list>
<bean id="bean1" class="com.xx.bean1" p:title="vvvv" p:tracks-ref="trackList"/>
導入和混合配置
1.JavaConfig中引用XML配置
- 僅使用JavaConfig實現兩個bean的引用關係:
@Configuration
public class Bean2Config{
@Bean
public Bean1 bean1(){
return new Bean1();
}
}
bean2構造需要引用到bean1,除了在構造器中外可以使用@import導入引用:
@Configuration
@Import(CDConfig.class)
public class Bean2Config{
@Bean
public Bean2 bean2(Bean1 bean1){
return new Bean2(bean1);
}
}
或者不在Bean2的config中Import而是使用另一個更高級的類,同事Import兩個類來使用另一種講兩個類關聯在一起:
@Configuration
@Import({Bean2Config.class,Bean1Config.class})
public class SystemBeanConfig{
}
- JavaConfig中引用XML中的配置:
當由於某些原因Bean1配置在XML中(cd-bean-config.xml):
<bean id="bean1" class="com.xx.Bean1" c:_0="hahah" c:_1="lll">
<contructor-arg>
<list>
<value>hahha</value>
<value>lllk</value>
...
</list>
</constructor-arg>
</beans>
在bean2中需要引用這個聲明好的bean1時,需使用@ImportResource來引入XML中配置的bean:
@Configuration
@Import(Bean2Config.class)
@ImportResource("classpath:cd-bean-config.xml")
public class SystemBeanConfig{
}
通過以上配置,bean1與bean2都會被加載到Spring容器之中。因爲Bean2中帶有@Bean註解的方法接受一個Bean1作爲參數,因此bean1將會裝配進來,與它是通過XML配置還是java代碼配置的沒有任何關係。
2.XML中引用JavaConfig配置
當正在使用Spring基於XML配置並已經意識到XML主鍵變得無法控制(配置太繁瑣)時,可以將XML配合指紋鍵進行拆分:
使用XML提供的bean元素的Class:
<bean class="com.xx.Bean2Config"/>
如果需要將一個在另一個XML中bean和JavaConfig配置的bean關聯在同一個XML中可以使用和元素:
<bean class="com.xx.Bean2Config/>
<import resource="cd-bean-config.xml"/>