我們書接上文:細(xì)說Spring——IoC詳解(四)草慧,接著講解配置文件。
一、<bean>
中的屬性
1宗收、depends-on
我們可以用depends-on
屬性來聲明當(dāng)前的對象所依賴的對象挂疆,比如我們當(dāng)前的對象A
在構(gòu)造時(shí)調(diào)用了對象B
的一個(gè)方法改览,那么我們就可以使用depends-on
來聲明這種依賴下翎,然后在容器構(gòu)造對象A
之前就會先去構(gòu)造對象B
,同時(shí)可以在depends-on
中通過逗號分割各個(gè)beanName
宝当,來達(dá)到多個(gè)依賴的效果视事,示例如下:
<bean id="classAInstance" class="...ClassA" depends-on="configSetup,configSetup2,..."/>
<bean id="configSetup" class="SystemConfigurationSetup"/>
<bean id="configSetup2" class="SystemConfigurationSetup2"/>
2、autowire
通過<bean>
的autowire
屬性庆揩,可以指定當(dāng)前bean
定義采用某種類型的自動綁定模式俐东。也就是可以幫助我們自動的注入依賴,而不用使用<constructor-arg>
和<property>
來顯式的聲明依賴订晌。
Spring提供了5種自動綁定模式虏辫,即no、byName锈拨、byType砌庄、constructor和autodetect
,下面是它們的具體介紹:
-
no
:容器默認(rèn)的自動綁定模式奕枢,也就是不采用任何形式的自動綁定娄昆,完全依賴手工明確配置各個(gè)bean
之間的依賴關(guān)系,以下代碼演示的兩種配置是等效的:<bean id="beanName" class="..."/>
或者<bean id="beanName" class="..." autowire="no"/>
-
byName
:按照類中聲明的實(shí)例變量的名稱缝彬,與XML配置文件中聲明的bean定義的beanName的值進(jìn)行匹配萌焰,相匹配的bean定義將被自動綁定到當(dāng)前實(shí)例變量上。這種方式對類定義和配置的bean定義有一定的限制谷浅。假設(shè)我們有如下所示的類定義:
public class Foo
{
private Bar emphasisAttribute;
...
// 相應(yīng)的setter方法定義
}
public class Bar
{
...
}
那么應(yīng)該使用如下代碼所演示的自動綁定定義扒俯,才能達(dá)到預(yù)期的目的:
<bean id="fooBean" class="...Foo" autowire="byName">
</bean>
<bean id="emphasisAttribute" class="...Bar">
</bean>
需要注意兩點(diǎn):第一,我們并沒有明確指定fooBean的依賴關(guān)系一疯,而僅指定了它的autowire屬性
為byName撼玄;第二,第二個(gè)bean定義的id為emphasisAttribute违施,與Foo類中的實(shí)例變量名稱相同互纯。
-
byType
:如果指定當(dāng)前bean定義的autowire模式為byType,那么磕蒲,容器會根據(jù)當(dāng)前bean定義類型留潦,分析其相應(yīng)的依賴對象類型,然后到容器所管理的所有bean定義中尋找與依賴對象類型相同的bean定義辣往,然后將找到的符合條件的bean自動綁定到當(dāng)前bean定義兔院。對于byName模式中的實(shí)例類Foo來說,容器會在其所管理的所有bean定義中尋找類型為Bar的bean定義站削。如果找到坊萝,則將找到的bean綁定到Foo的bean定義;如果沒有找到,則不做設(shè)置十偶。但如果找到多個(gè)菩鲜,容器會告訴你它解決不了“該選用哪一個(gè)”的問題,你只好自己查找原因惦积,并自己修正該問題接校。所以,byType只能保證狮崩,在容器中只存在一個(gè)符合條件的依賴對象的時(shí)候才會發(fā)揮最大的作用蛛勉,如果容器中存在多個(gè)相同類型的bean定義,那么睦柴,不好意思诽凌,采用手動明確配置吧!指定byType類型的autowire模式與byName沒什么差別坦敌,只是autowire的值換成byType而已侣诵,可
以參考如下代碼:
<bean id="fooBean" class="...Foo" autowire="byType">
</bean>
<bean id="anyName" class="...Bar"> </bean>
-
constructor
:byName和byType類型的自動綁定模式是針對property的自動綁定,而constructor類型則是針對構(gòu)造方法參數(shù)的類型而進(jìn)行的自動綁定恬试,它同樣是byType類型的綁定模式窝趣。不過疯暑,constructor是匹配構(gòu)造方法的參數(shù)類型训柴,而不是實(shí)例屬性的類型。與byType模式類似妇拯,如果找到不止一個(gè)符合條件的bean定義幻馁,那么,容器會返回錯(cuò)誤越锈。使用上也與byType沒有太大差別仗嗦,只不過是應(yīng)用到需要使用構(gòu)造方法注入的bean定義之上,示例如下:
public class Foo
{
private Bar bar;
public Foo(Bar arg)
{
this.bar = arg;
}
...
}
相應(yīng)配置為
<bean id="foo" class="...Foo" autowire="constructor"/>
<bean id="bar" class="...Bar">
</bean>
-
autodetect
:這種模式是byType和constructor模式的結(jié)合體甘凭,如果對象擁有默認(rèn)無參數(shù)的構(gòu)造方法稀拐,容器會優(yōu)先考慮byType的自動綁定模式。否則丹弱,會使用constructor模式德撬。當(dāng)然,如果通過構(gòu)造方法注入綁定后還有其他屬性沒有綁定躲胳,容器也會使用byType對剩余的對象屬性進(jìn)行自動綁定蜓洪。
<beans>
有一個(gè)default-autowire
屬性,它可以幫我們省去為多個(gè)<bean>
單獨(dú)設(shè)置autowire
屬性的麻煩坯苹,default-autowire
的默認(rèn)值為no
隆檀,即不進(jìn)行自動綁定。
3、dependency-check
我們可以使用每個(gè)<bean>
的dependency-check
屬性對其所依賴的對象進(jìn)行最終檢查恐仑,該功能可以幫我們檢查每個(gè)對象某種類型的所有依賴是否全部已經(jīng)注入完成泉坐,不過可能無法細(xì)化到具體的類型檢查。有如下4種類型的依賴檢查:
-
none
:不做依賴檢查裳仆。將dependency-check指定為none跟不指定這個(gè)屬性等效坚冀,所以,還是不要多敲那幾個(gè)字符了吧鉴逞。默認(rèn)情況下记某,容器以此為默認(rèn)值。 -
simple
:如果將dependency-check的值指定為simple构捡,那么容器會對簡單屬性類型以及相
關(guān)的collection進(jìn)行依賴檢查液南,對象引用類型的依賴除外。 -
object
:只對對象引用類型依賴進(jìn)行檢查勾徽。 -
all
:將simple和object相結(jié)合滑凉,也就是說會對簡單屬性類型以及相應(yīng)的collection和所有對
象引用類型的依賴進(jìn)行檢查。
4喘帚、 lazy-init
延遲初始化畅姊,這個(gè)主要作用于ApplicationContext容器
,BeanFactory容器
的初始化策略默認(rèn)是延遲初始化吹由。<beans>
中也有一個(gè) default-lazy-init
屬性若未,可以統(tǒng)一控制所有的<beans>
進(jìn)行延遲初始化。示例如下:
<beans default-lazy-init="true">
<bean id="lazy-init-bean" class="..." lazy-init="false"/>
<bean id="not-lazy-init-bean" class="...">
<property name="propName">
<ref bean="lazy-init-bean"/>
</property>
</bean>
...
</beans>
好了到了這里<bean>
中比較一般的屬性就介紹完了倾鲫,接下來是一些比較重要的屬性粗合,我們就著重來看一下。
5乌昔、abstract
和parent
在面向?qū)ο蟮木幊淘碇邢毒危?dāng)多個(gè)類擁有相同的方法和屬性,則可以引入父類消除代碼重復(fù)磕道。在Spring容器中供屉,如果多個(gè)Bean存在相同的配置信息,同樣可以定義一個(gè)父Bean溺蕉,子Bean將自動繼承父Bean的配置信息伶丐。父bean中的所有屬性值也會出現(xiàn)在子bean當(dāng)中,那么假如子bean當(dāng)中配置了父bean已有的屬性的話焙贷,會覆蓋掉父bean中的配置撵割。我們可以通過<parent>
來指定繼承關(guān)系,示例如下:
1辙芍、 未使用父子<bean>
的配置
<bean id=“car1” class=“cn.lovepi.***.Car”
p:brand=“奔馳E300” p:price=“2000” p:color=“黑色”/>
<bean id=“car1” class=“cn.lovepi.***.Car”
p:brand=“奔馳E300” p:price=“2000” p:color=“紅色”/>
可以看到啡彬,兩個(gè)car bean除了color屬性不同之外羹与,其他屬性都是完全一樣的。
2庶灿、使用父子<bean>
的配置
<bean id=“abstractCar” class=“cn.lovepi.***.Car”
p:brand=“奔馳E300” p:price=“2000” p:color=“黑色” abstract=“true”/>
<bean id=“car1” p:color=“紅色” parent=“abstractCar” />
<bean id=“car1” p:color=“白色” parent=“abstractCar” />
可以看到car1和car2這兩個(gè)bean都繼承自abstractCar這個(gè)父bean纵搁,在上面的代碼中子bean就只改變了color屬性,其他屬性都跟父類相同往踢。
通過abstract屬性聲明為true腾誉,說明這個(gè)bean定義不需要實(shí)例化。峻呕。如果你不想容器在初始化的時(shí)候?qū)嵗承ο罄埃敲纯梢詫⑵鋋bstract屬性賦值true,以避免容器將其實(shí)例化瘦癌。對于ApplicationContext容器尤其如此猪贪,因?yàn)槟J(rèn)情況下,ApplicationContext會在容器啟動的時(shí)候就對其管理的所有bean進(jìn)行實(shí)例化讯私,只有標(biāo)志為abstract的bean和設(shè)定為延遲加載的bean除外热押。
6、scope
這里就在偷個(gè)懶吧斤寇,貼個(gè)鏈接:Spring學(xué)習(xí)(十五)Spring Bean 的5種作用域介紹
這個(gè)博客詳細(xì)的講解了<bean>
的scope
屬性桶癣。
7娘锁、factory-method
和factory-bean
這里就需要介紹致盟,依賴的注入除了我們常用的構(gòu)造器方法注入和setter方法注入以外,還可以使用工廠方法進(jìn)行注入杯道,這里分為了兩種责蝠,一個(gè)是靜態(tài)工廠方法注入霜医,一個(gè)是非靜態(tài)工廠方法注入,下面就分別介紹一下吧:
- 靜態(tài)工廠方法注入
public class StaticBarInterfaceFactory
{
public static BarInterface getInstance()
{
return new BarInterfaceImpl();
}
}
為了將該靜態(tài)工廠方法類返回的實(shí)現(xiàn)注入Foo署海,我們使用以下方式進(jìn)行配置
<bean id="foo" class="...Foo">
<property name="barInterface">
<ref bean="bar"/>
</property>
</bean>
<bean id="bar" class="...StaticBarInterfaceFactory" factory-method="getInstance"/>
class指定靜態(tài)方法工廠類捻勉,factory-method指定工廠方法名稱踱启,然后,容器調(diào)用該靜態(tài)方法工
廠類的指定工廠方法(getInstance)榜晦,并返回方法調(diào)用后的結(jié)果胚想,即BarInterfaceImpl的實(shí)例。
也就是說胚吁,為foo注入的bar實(shí)際上是BarInterfaceImpl的實(shí)例牙躺,即方法調(diào)用后的結(jié)果孽拷,而不是靜態(tài)工廠方法類(StaticBarInterfaceFactory)窿侈。
- 非靜態(tài)工廠方法注入
public class NonStaticBarInterfaceFactory
{
public BarInterface getInstance()
{
return new BarInterfaceImpl();
}
...
}
<bean id="foo" class="...Foo">
<property name="barInterface">
<ref bean="bar"/>
</property>
</bean>
<bean id="barFactory" class="...NonStaticBarInterfaceFactory"/>
<bean id="bar" factory-bean="barFactory" factory-method="getInstance"/>
NonStaticBarInterfaceFactory是作為正常的bean注冊到容器的史简,而bar的定義則與靜態(tài)工廠方
法的定義有些不同。現(xiàn)在使用factory-bean屬性來指定工廠方法所在的工廠類實(shí)例刀脏,而不是通過
class屬性來指定工廠方法所在類的類型愈污。指定工廠方法名則相同茫陆,都是通過factory-method屬性進(jìn)行的桨醋。
二瞬内、總結(jié)
這里就對<bean>
標(biāo)簽中的屬性進(jìn)行一個(gè)總結(jié):
- Id:通過id來訪問SpringBeanFactory中的java bean
- name: 通過name來訪問SpringBeanFactory中的java bean限书,在某種意義上來講name就是id的別稱虫蝶。
- class:java bean定義的全限定名,即包名+類名倦西。假如配置文件中沒有指定id或name的取值能真,那么class即作為id的取值。
- parent:如果沒有指定class屬性的話則可以使用parent扰柠,他們的含義是等效的粉铐。而且parent java bean 定義不僅能夠繼承parent當(dāng)中定義的所有內(nèi)容,而且還能夠覆蓋parent當(dāng)中定義的相關(guān)內(nèi)容卤档。比如覆蓋java bean方法:init蝙泼、destory等內(nèi)容。當(dāng)然某些parent設(shè)置是不能被覆蓋的裆装,比如:依賴關(guān)系踱承、autowire的值、作用域哨免。
- abstract:當(dāng)值為true的時(shí)候,表明相應(yīng)的java bean定義只是供parent使用昙沦,其本身是不能夠被實(shí)例化的琢唾。默認(rèn)值為false。
- scope:bean的作用域盾饮,Spring當(dāng)中提供了5種作用域采桃。
- lazy-init:延遲加載屬性懒熙,只有當(dāng)用到這個(gè)bean的時(shí)候,Spring才會進(jìn)行實(shí)例化普办。
- autowire:開發(fā)者是否使用Spring提供的autowire功能工扎,建議不使用,默認(rèn)值為no
- dependency-check:Spring是否需要對java bean 以及java bean之間的依賴關(guān)系來進(jìn)行判斷衔蹲。定義此屬性將會覆蓋在beans中定義的default-dependency-check屬性肢娘。
- depends-on:用于保證相應(yīng)的java bean在其指定depends-on的java bean實(shí)例化之后,才去實(shí)例化使用了depends-on的java bean的本身舆驶。
- init-method:主要用于設(shè)置在實(shí)例化java bean橱健,并設(shè)置java bean的屬性之后,待執(zhí)行的初始化方法沙廉。
- destroy-method:當(dāng)中SpringBeanFactory銷毀的時(shí)候,可以利用此方法來進(jìn)行一些資源回收的操作拘荡。或者一些其他的操作撬陵,比如關(guān)閉同GMS目的地的監(jiān)聽以及連接珊皿。在這里請注意,指令的方法應(yīng)該是參數(shù)類型巨税。
- factory-method:指定用于創(chuàng)建java bean 工廠的methed方法亮隙。在Spring當(dāng)中,對象的創(chuàng)建最好是通過bean factory來創(chuàng)建垢夹。
- factory-bean:指定用于創(chuàng)建java bean實(shí)例的工廠類溢吻。