spring在IoC容器中裝配Bean詳解
1、Spring配置概述
1.1、概述
Spring容器從xml配置、java注解、spring注解中讀取bean配置信息,形成bean定義注冊(cè)表;
根據(jù)bean定義注冊(cè)表實(shí)例化bean;
將bean實(shí)例放入bean緩存池;
應(yīng)用程序使用bean。
1.2、基于xml的配置
(1)xml文件概述
xmlns------默認(rèn)命名空間
xmlns:xsi-------標(biāo)準(zhǔn)命名空間,用于指定自定義命名空間的schema文件
xmlns:xxx=“aaaaa”-------自定義命名空間,xxx是別名,后面的值aaaa是全名
xsi:schemaLocation----------為每個(gè)命名空間指定具體的schema文件,格式:命名空間全名文件地址。。。用空格隔開(kāi)
2、Bean基本配置
2.1、Bean的命名
(1)id和name都可以指定多個(gè)名字,名字之間用逗號(hào),分號(hào)或空格進(jìn)行分隔
<beanname="#car,123,$car"class="xxxxxxxxx">
用戶(hù)可以使用getBean("#car"),getBean("123"),getBean("$car")獲取bean。
(2)如果沒(méi)有指定id和name屬性,則spring自動(dòng)將類(lèi)的全限定名作為bean的名稱(chēng)
(3)如果存在多個(gè)匿名bean,即沒(méi)有指定id和name的<bean/>,假設(shè)類(lèi)的全限定名為xxx,
則獲取第一個(gè)bean使用getBean("xxx"),獲取第二個(gè)bean使用getBean("xxx#1"),獲取第三個(gè)bean使用getBean("xxx#2")。
3、依賴(lài)注入
3.1、屬性注入
(1)屬性注入要求Bean提供一個(gè)默認(rèn)的構(gòu)造函數(shù),并為需要注入的屬性提供Setter方法。spring先調(diào)用默認(rèn)構(gòu)造函數(shù)實(shí)例化bean對(duì)象,然后通過(guò)反射的方式調(diào)用Setter方法注入屬性值。
(2)spring只會(huì)檢查bean中是否有對(duì)應(yīng)的Setter方法,至于bean中是否有對(duì)應(yīng)的屬性變量則不做要求。
(3)javabean關(guān)于屬性命名的特殊規(guī)范:變量的前2個(gè)字母要么全部大寫(xiě),要么全部小寫(xiě)。
3.2、構(gòu)造函數(shù)注入
(1)構(gòu)造函數(shù)參數(shù)的配置順序不會(huì)對(duì)配置結(jié)果產(chǎn)生影響,spring的配置文件采用和元素標(biāo)簽順序無(wú)關(guān)的策略,這種策略可以在一定程度上保證配置信息的確定性。
(2)按索引匹配入?yún)?/p>
如果構(gòu)造函數(shù)的入?yún)㈩?lèi)型相同,則需要指定參數(shù)的順序索引,否則無(wú)法確定對(duì)應(yīng)關(guān)系。如:
<constructor-argindex="0"value="xxxxxx"> <constructor-argindex="1"value="xxxxxx">
索引從0開(kāi)始。
(3)循環(huán)依賴(lài)問(wèn)題
如果有2個(gè)bean的構(gòu)造函數(shù)配置都依賴(lài)對(duì)方,則會(huì)出現(xiàn)類(lèi)似線程死鎖的問(wèn)題,
解決的辦法就是將構(gòu)造函數(shù)注入改為屬性注入。
3.3、工廠方法注入
(1)非靜態(tài)工廠方法
由于工廠方法不是靜態(tài)的,所以得先創(chuàng)建一個(gè)工廠類(lèi)的實(shí)例bean,并使用factory-bean來(lái)引用
<beanid="carFactory"class="工廠類(lèi)"/> <beanid="car5"factory-bean="carFactory"factory-method="createCar"/>
(2)靜態(tài)工廠方法
<beanid="car5"class="工廠類(lèi)"factory-method="createCar"/>
3.4、注入?yún)?shù)詳解
(1)xml中的5個(gè)特殊字符
特殊符號(hào)
|
轉(zhuǎn)義序列
|
特殊符號(hào)
|
轉(zhuǎn)義序列
|
< |
<
|
""
|
"
|
> |
>
|
'
|
'
|
&
|
&
|
|
(2)<![CDATA[]]>
<![CDATA[]]>的作用是讓XML解析器將標(biāo)簽中的字符串當(dāng)作普通文本對(duì)待。
(3)使用<null/>標(biāo)簽注入null值
(4)級(jí)聯(lián)屬性
<beanid="parent"class="xxxxxxx"> <propertyname="child.xxx"value="依賴(lài)對(duì)象的屬性值"/> </bean>
spring3.0之前,必須先實(shí)例化依賴(lài)對(duì)象child,否則會(huì)拋出異常,spring3.0之后,則不需要在顯示實(shí)例化,spring容器會(huì)自動(dòng)實(shí)例化依賴(lài)對(duì)象。
(5)集合合并
<setmerge="true"/>
常見(jiàn)于子類(lèi)合并父類(lèi)的集合元素
(6)通過(guò)util命名空間配置集合類(lèi)型的bean
如果希望配置一個(gè)集合類(lèi)型的Bean,而不是一個(gè)集合類(lèi)型的屬性,則可以通過(guò)util命名空間進(jìn)行配置。
3.5、自動(dòng)裝配
(1)<bean/>元素提供了一個(gè)指定自動(dòng)裝配類(lèi)型的屬性autowire
3.6、方法注入
如果我們往單例模式的bean中注入prototype的bean,并希望每次調(diào)用時(shí)都能夠返回一個(gè)新的bean,使用傳統(tǒng)的注入方式將無(wú)法實(shí)現(xiàn),因?yàn)閱卫腷ean注入關(guān)聯(lián)bean的動(dòng)作僅發(fā)生一次。
(1)一種可選的解決方法就是讓宿主bean實(shí)現(xiàn)BeanFactoryAware接口,讓宿主bean能夠訪問(wèn)容器的引用,這樣就可以修改get方法,使用容器的
factory.getBean("被依賴(lài)bean")方法,每次都能獲得最新的bean。
(2)上面那種方式使我們的代碼和spring耦合,實(shí)為下策,我們可以通過(guò)方法注入的方式解耦。
我們只需定義一個(gè)接口,接口中定義一個(gè)獲取依賴(lài)bean的抽象方法,spring配置如下:
<beanid="car"class="被依賴(lài)bean"/> <beanid="host"class="接口bean"> <lookup-methodname="getCar"bean="car"/> </bean>
通過(guò)lookup-method元素標(biāo)簽為接口bean的getCar()提供動(dòng)態(tài)實(shí)現(xiàn),方法注入的實(shí)現(xiàn)主要依賴(lài)Cglib包的動(dòng)態(tài)操作字節(jié)碼技術(shù)。
3.7、方法替換
使用bean2替換bean1的getCar方法,前提是bean2得實(shí)現(xiàn)MethodReplacer接口,配置如下:
<beanid="bean1"class="aaaaaaaaaa"> <replaced-methodname="getCar"replacer="bean2"/> </bean> <beanid="bean2"class="bbbbbbbbb"/>
4、<bean>之間的關(guān)系
4.1、繼承
父bean的配置可以被子類(lèi)繼承,避免重復(fù)定義,配置如下:
<beanid="父bean"class="aaaaaaa"abstract="true"/> <beanid="子bean"class="bbbbbb">
子類(lèi)可以覆蓋父類(lèi)的配置,如果不指定父類(lèi)的abstract="true",則父bean會(huì)被實(shí)例化。
4.2、依賴(lài)
有些bean的實(shí)例化依賴(lài)其他bean,其他bean必須先實(shí)例化好后才能實(shí)例化宿主bean,spring提供了depends-on的屬性,指定依賴(lài)bean先實(shí)例化,如:
<beanid="host"class="aaaaaaa"depends-on="b1"/> <beanid="b1"class="bbbbbbb"/>
如果有多個(gè)前置依賴(lài)bean,則可以通過(guò)逗號(hào),空格或分號(hào)的方式創(chuàng)建bean的名稱(chēng)。
4.3、Bean作用域
(1)spring容器在啟動(dòng)時(shí)就會(huì)實(shí)例化所有的bean,如果不想提前實(shí)例化,<bean/>的lazy-init="true"屬性可以控制延遲實(shí)例化,但是如果該bean被其他需要提前實(shí)例化的bean引用,則spring也將忽略延遲實(shí)例化的設(shè)置。
(2)web應(yīng)用相關(guān)的作用域
如果用戶(hù)使用request,session,globalSession作用域,首先必須在web容器中進(jìn)行額外的配置:
在低版本的web容器(Servlet2.3之前),可以使用http請(qǐng)求過(guò)濾器配置:
<filter> <filter-name>requestContextFilter</filter-name> <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class> </filter> <filter-mapping> <filter-name>requestContextFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
在高版本的web容器中,可以使用http請(qǐng)求監(jiān)聽(tīng)器進(jìn)行配置:
<listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener>
(3)作用域依賴(lài)問(wèn)題
當(dāng)將web作用域的bean注入到singleton或prototype的bean中時(shí),要借助于aop,例如:
<bean id="web1" class="aaaaaa" scope="request" > <aop:scoped-proxy/> </bean> <bean id="singleton1" class="bbbbbb" > <property name="z1" ref="web1" /> </bean>
4.4、FactoryBean
一般情況下,spring通過(guò)反射機(jī)制利用<bean/>的class屬性指定實(shí)現(xiàn)類(lèi)實(shí)例化bean就可以了。但在某些情況下,實(shí)例化bean的過(guò)程比較復(fù)雜,如果按照傳統(tǒng)的方式,則需要在<bean>中提供大量的配置信息。配置方式的靈活性是受限的,這時(shí)采用編碼的方式可能會(huì)得到一個(gè)簡(jiǎn)單的方案。
Spring為此提供了一個(gè)org.springframework.beans.factory.FactoryBean工廠類(lèi)接口,用戶(hù)可以通過(guò)實(shí)現(xiàn)該接口,定制實(shí)例化bean的邏輯。
當(dāng)<bean/>的class屬性配置的實(shí)現(xiàn)類(lèi)是FactoryBean及其子類(lèi)時(shí),通過(guò)getBean()方法返回的不是FactoryBean及其子類(lèi)本身,而是返回FactoryBean的getObject()方法返回的對(duì)象。
如果希望獲取FactoryBean及其子類(lèi)本身的對(duì)象,則在getBean(beanName)方法時(shí)顯式地在beanName前加上“&”前綴,如getBean("&car5")。
5、基于注解的配置
5.1、注解類(lèi)型
@Component------原生注解
衍型注解:
@Repository:標(biāo)注DAO
@Service:標(biāo)注service
@Controller:標(biāo)注控制器
5.2、使用注解配置信息啟動(dòng)spring容器
(1)spring2.5以后引入了context命名空間,它提供了通過(guò)掃描類(lèi)包以應(yīng)用注解定義bean:
<context:component-scan base-package="xxxxxxxxxx" resource-pattern="xxxx/*.class">
resource-pattern屬性用于指定在基包中需要掃描的特定包下的類(lèi)
(2)還有更加強(qiáng)大過(guò)濾子標(biāo)簽
<context:component-scan base-package="xxxxxxxxxx" > <context:include-filter type="xxxx" expression="xxxxxxxxxxxxxxxx"/> <context:exclude-filter type="xxxx" expression="xxxxxxxxxxxxxxxx"/> </context:component-scan>
在所有的類(lèi)型中,aspectj的過(guò)濾能力是最強(qiáng)大的。
5.3、自動(dòng)裝配Bean
(1)@Autowired
@Autowired默認(rèn)按類(lèi)型匹配的方式,如果容器中沒(méi)有一個(gè)匹配的bean,spring容器啟動(dòng)時(shí)將拋出異常,那么可以使用@Autowired(required=false)進(jìn)行標(biāo)注,則不會(huì)拋出異常。
使用@Autowired還可以對(duì)方法入?yún)⒅苯訕?biāo)注,如果一個(gè)方法有多個(gè)入?yún)?,在默認(rèn)情況下,spring自動(dòng)選擇匹配入?yún)㈩?lèi)型的bean進(jìn)行注入。
使用@Autowired標(biāo)注集合變量,可以將所有匹配該集合元素類(lèi)型的bean都注入進(jìn)來(lái),很強(qiáng)大。
使用@Autowired裝配屬性,可以沒(méi)有setter方法。
(2)@Qualifiler
如果容器中有一個(gè)以上匹配的bean,則可以通過(guò)@Qualifiler注解限定bean的名稱(chēng)。
(3)對(duì)標(biāo)注注解的支持
spring還支持JSR-250定義的@Resource和JSR-330定義的@Inject注解
@Resource要求提供一個(gè)bean的名稱(chēng)屬性,如果屬性為空,則自動(dòng)采用變量名或者方法名作為bean的名稱(chēng)。
(4)要點(diǎn):
如果僅僅使用@Autowired,我們?nèi)匀恍枰@式地在xml中定義<bean/>節(jié)點(diǎn),spring容器默認(rèn)禁用注解裝配,啟用的方式是在xml中配置<context:annotation-config/>元素。
但是spring還提供了另一種技巧,使用<context:component-scan/>元素,spring容器就會(huì)自動(dòng)檢測(cè)bean,而不需要顯式的定義<bean/>節(jié)點(diǎn)。
spring通過(guò)@Component、@Repository、@Service、@Controller注解標(biāo)注類(lèi),讓<context:component-scan/>知道哪些類(lèi)需要注冊(cè)為SpringBean。
如果使用了第三方的jar包,且希望自動(dòng)注入第三方j(luò)ar包中的類(lèi),即使第三方j(luò)ar包的類(lèi)中沒(méi)有使用注解標(biāo)注它們,過(guò)濾器元素<context:include-filter>可以替換掉基于注解的組件掃描策略,讓<context:component-scan/>自動(dòng)注冊(cè)符合expression表達(dá)式的類(lèi)。
5.4、Bean作用范圍及生命過(guò)程方法
(1)@Scope("xxxx")
通過(guò)注解配置的Bean和通過(guò)xml配置的Bean一樣,默認(rèn)的作用范圍都是singleton。
spring提供了@Scope注解,作用于類(lèi)上,注解的參數(shù)就和xml中<bean/>的scope屬性的值一樣。
(2)生命過(guò)程方法對(duì)比
<bean>
|
注解 |
init-method
|
@PostConstruct
|
destory-method
|
@PreDestroy
|
區(qū)別:注解在類(lèi)中可以定義多個(gè)方法,且方法按順序執(zhí)行
6、基于java類(lèi)的配置
6.1、使用java類(lèi)提供Bean定義信息
(1)普通的POJO只要標(biāo)注@Configuration注解,就可以為spring容器提供bean定義的信息,每個(gè)標(biāo)注了@Bean的方法都相當(dāng)于提供一個(gè)Bean的定義信息。
(2)@Bean
Bean的類(lèi)型由@Bean標(biāo)注的方法的返回值類(lèi)型決定
Bean的名稱(chēng)默認(rèn)和方法名相同,也可以通過(guò)@Bean(name="xxx")來(lái)顯式指定
可以在@Bean處使用@Scope,標(biāo)注Bean的使用范圍
(3)@Configuration
由于@Configuration注解類(lèi)本身已經(jīng)標(biāo)注了@Component注解,所以任何標(biāo)注了@Configurstion的類(lèi),都可以使用@Autowired被自動(dòng)裝配到其他類(lèi)中。
6.2、使用基于java類(lèi)的配置信息啟動(dòng)spring容器
(1)spring提供了一個(gè)AnnotationConfigApplicationContect類(lèi),它能夠直接通過(guò)標(biāo)注@Configuration注解的類(lèi)啟動(dòng)Spring容器。
(2)當(dāng)有多個(gè)配置類(lèi)時(shí)
可以通過(guò)AnnotationConfigApplicationContect的register方法一個(gè)個(gè)注冊(cè),然后再調(diào)用refresh方法刷新容器以應(yīng)用這些注冊(cè)的配置類(lèi)。
也可以通過(guò)@Import(xxx.class)注解,將其他配置類(lèi)全部引入到一個(gè)配置類(lèi)中,這樣僅需要注冊(cè)一個(gè)配置類(lèi)即可
(3)通過(guò)xml配置類(lèi)引用@Configuration的配置
<context:component-scanbase-package="......"resource-pattern="配置類(lèi)名">
(4)在配置類(lèi)中引用xml配置信息
在@Configuration處使用@ImportResource("classpath:................")來(lái)引入xml配置文件
6.3、3種配置方式的比較
XML
|
注解
|
java類(lèi)
|
|
Bean的實(shí)現(xiàn)類(lèi)是當(dāng)前項(xiàng)目開(kāi)發(fā)
|
通過(guò)代碼方式控制Bean初始化整體邏輯,適用于實(shí)例化Bean比較復(fù)雜的場(chǎng)景
|
總結(jié)
以上就是本文關(guān)于spring在IoC容器中裝配Bean詳解的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站:
如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!
相關(guān)文章
spring @Cacheable擴(kuò)展實(shí)現(xiàn)緩存自動(dòng)過(guò)期時(shí)間及自動(dòng)刷新功能
用過(guò)spring cache的朋友應(yīng)該會(huì)知道,Spring Cache默認(rèn)是不支持在@Cacheable上添加過(guò)期時(shí)間的,雖然可以通過(guò)配置緩存容器時(shí)統(tǒng)一指定,本文主要介紹了如何基于spring @Cacheable擴(kuò)展實(shí)現(xiàn)緩存自動(dòng)過(guò)期時(shí)間以及緩存即將到期自動(dòng)刷新,2024-02-02Java字節(jié)流 從文件輸入輸出到文件過(guò)程解析
這篇文章主要介紹了Java字節(jié)流 從文件輸入 輸出到文件過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09SpringBoot詳細(xì)講解靜態(tài)資源導(dǎo)入的實(shí)現(xiàn)
在Web開(kāi)發(fā)過(guò)程中,我們需要接觸許多靜態(tài)資源,如CSS、JS、圖片等;在之前的開(kāi)發(fā)中,這些資源都放在Web目錄下,用到的時(shí)候按照對(duì)應(yīng)路徑訪問(wèn)即可。不過(guò)在SpringBoot項(xiàng)目中,沒(méi)有了Web目錄,那這些靜態(tài)資源該放到哪里去,又要如何訪問(wèn)呢?這就是我們要講的靜態(tài)資源導(dǎo)入2022-05-05java實(shí)現(xiàn)protocol傳輸?shù)目蛻?hù)端和服務(wù)端的示例代碼
本文主要介紹了java實(shí)現(xiàn)protocol傳輸?shù)目蛻?hù)端和服務(wù)端的示例代碼,基于TCP協(xié)議的客戶(hù)端和服務(wù)端,包括了基本的連接、消息傳遞和關(guān)閉連接的操作,感興趣的可以了解一下2024-07-07解決IntelliJ?IDEA輸出中文顯示為問(wèn)號(hào)問(wèn)題的有效方法
最近剛學(xué)到文件字節(jié)流這里,但輸出中文時(shí),出現(xiàn)了控制臺(tái)輸出問(wèn)號(hào)的情況,所以下面這篇文章主要給大家介紹了關(guān)于如何解決IntelliJ?IDEA輸出中文顯示為問(wèn)號(hào)問(wèn)題的有效方法,需要的朋友可以參考下2022-07-07