1、Spring配置概述
1.1、概述
Spring容器從xml配置、java註解、spring註解中讀取bean配置信息,形成bean定義註冊表;
根據bean定義註冊表實例化bean;
將bean實例放入bean緩存池;
應用程序使用bean。
1.2、基於xml的配置
(1)xml文件概述
xmlns------默認命名空間
xmlns:xsi-------標準命名空間,用於指定自定義命名空間的schema文件
xmlns:xxx=“aaaaa”-------自定義命名空間,xxx是別名,後面的值aaaa是全名
xsi:schemaLocation----------為每個命名空間指定具體的schema文件,格式:命名空間全名文件地址。 。 。用空格隔開
2、Bean基本配置
2.1、Bean的命名
(1)id和name都可以指定多個名字,名字之間用逗號,分號或空格進行分隔
<beanname="#car,123,$car"class="xxxxxxxxx">
用戶可以使用getBean("#car"),getBean("123"),getBean("$car")獲取bean。
(2)如果沒有指定id和name屬性,則spring自動將類的全限定名作為bean的名稱
(3)如果存在多個匿名bean,即沒有指定id和name的<bean/>,假設類的全限定名為xxx,
則獲取第一個bean使用getBean("xxx"),獲取第二個bean使用getBean("xxx#1"),獲取第三個bean使用getBean("xxx#2")。
3、依賴注入
3.1、屬性注入
(1)屬性注入要求Bean提供一個默認的構造函數,並為需要注入的屬性提供Setter方法。 spring先調用默認構造函數實例化bean對象,然後通過反射的方式調用Setter方法注入屬性值。
(2)spring只會檢查bean中是否有對應的Setter方法,至於bean中是否有對應的屬性變量則不做要求。
(3)javabean關於屬性命名的特殊規範:變量的前2個字母要么全部大寫,要么全部小寫。
3.2、構造函數注入
(1)構造函數參數的配置順序不會對配置結果產生影響,spring的配置文件採用和元素標籤順序無關的策略,這種策略可以在一定程度上保證配置信息的確定性。
(2)按索引匹配入參
如果構造函數的入參類型相同,則需要指定參數的順序索引,否則無法確定對應關係。如:
<constructor-argindex="0"value="xxxxxx"><constructor-argindex="1"value="xxxxxx">
索引從0開始。
(3)循環依賴問題
如果有2個bean的構造函數配置都依賴對方,則會出現類似線程死鎖的問題,
解決的辦法就是將構造函數注入改為屬性注入。
3.3、工廠方法注入
(1)非靜態工廠方法
由於工廠方法不是靜態的,所以得先創建一個工廠類的實例bean,並使用factory-bean來引用
<beanid="carFactory"class="工廠類"/><beanid="car5"factory-bean="carFactory"factory-method="createCar"/>
(2)靜態工廠方法
<beanid="car5"class="工廠類"factory-method="createCar"/>
3.4、注入參數詳解
(1)xml中的5個特殊字符
| 特殊符號 | 轉義序列 | 特殊符號 | 轉義序列 |
| < | < | "" | |
| > | > | ' | ' |
| & | & |
(2)<![CDATA[]]>
<![CDATA[]]>的作用是讓XML解析器將標籤中的字符串當作普通文本對待。
(3)使用<null/>標籤注入null值
(4)級聯屬性
<beanid="parent"class="xxxxxxx"><propertyname="child.xxx"value="依賴對象的屬性值"/></bean>
spring3.0之前,必須先實例化依賴對象child,否則會拋出異常,spring3.0之後,則不需要在顯示實例化,spring容器會自動實例化依賴對象。
(5)集合合併
<setmerge="true"/>
常見於子類合併父類的集合元素
(6)通過util命名空間配置集合類型的bean
如果希望配置一個集合類型的Bean,而不是一個集合類型的屬性,則可以通過util命名空間進行配置。
3.5、自動裝配
(1)<bean/>元素提供了一個指定自動裝配類型的屬性autowire
3.6、方法注入
如果我們往單例模式的bean中註入prototype的bean,並希望每次調用時都能夠返回一個新的bean,使用傳統的注入方式將無法實現,因為單例的bean注入關聯bean的動作僅發生一次。
(1)一種可選的解決方法就是讓宿主bean實現BeanFactoryAware接口,讓宿主bean能夠訪問容器的引用,這樣就可以修改get方法,使用容器的
factory.getBean("被依賴bean")方法,每次都能獲得最新的bean。
(2)上面那種方式使我們的代碼和spring耦合,實為下策,我們可以通過方法注入的方式解耦。
我們只需定義一個接口,接口中定義一個獲取依賴bean的抽象方法,spring配置如下:
<beanid="car"class="被依賴bean"/><beanid="host"class="接口bean"><lookup-methodname="getCar"bean="car"/></bean>
通過lookup-method元素標籤為接口bean的getCar()提供動態實現,方法注入的實現主要依賴Cglib包的動態操作字節碼技術。
3.7、方法替換
使用bean2替換bean1的getCar方法,前提是bean2得實現MethodReplacer接口,配置如下:
<beanid="bean1"class="aaaaaaaaaa"><replaced-methodname="getCar"replacer="bean2"/></bean><beanid="bean2"class="bbbbbbbbb"/>
4、<bean>之間的關係
4.1、繼承
父bean的配置可以被子類繼承,避免重複定義,配置如下:
<beanid="父bean"class="aaaaaaa"abstract="true"/><beanid="子bean"class="bbbbbb">
子類可以覆蓋父類的配置,如果不指定父類的abstract="true",則父bean會被實例化。
4.2、依賴
有些bean的實例化依賴其他bean,其他bean必須先實例化好後才能實例化宿主bean,spring提供了depends-on的屬性,指定依賴bean先實例化,如:
<beanid="host"class="aaaaaaa"depends-on="b1"/><beanid="b1"class="bbbbbbb"/>
如果有多個前置依賴bean,則可以通過逗號,空格或分號的方式創建bean的名稱。
4.3、Bean作用域
(1)spring容器在啟動時就會實例化所有的bean,如果不想提前實例化,<bean/>的lazy-init="true"屬性可以控制延遲實例化,但是如果該bean被其他需要提前實例化的bean引用,則spring也將忽略延遲實例化的設置。
(2)web應用相關的作用域
如果用戶使用request,session,globalSession作用域,首先必須在web容器中進行額外的配置:
在低版本的web容器(Servlet2.3之前),可以使用http請求過濾器配置:
<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請求監聽器進行配置:
<listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener>
(3)作用域依賴問題
當將web作用域的bean注入到singleton或prototype的bean中時,要藉助於aop,例如:
<bean id="web1" scope="request" > <aop:scoped-proxy/></bean><bean id="singleton1" > <property name="z1" ref="web1" /></bean>
4.4、FactoryBean
一般情況下,spring通過反射機制利用<bean/>的class屬性指定實現類實例化bean就可以了。但在某些情況下,實例化bean的過程比較複雜,如果按照傳統的方式,則需要在<bean>中提供大量的配置信息。配置方式的靈活性是受限的,這時採用編碼的方式可能會得到一個簡單的方案。
Spring為此提供了一個org.springframework.beans.factory.FactoryBean工廠類接口,用戶可以通過實現該接口,定制實例化bean的邏輯。
當<bean/>的class屬性配置的實現類是FactoryBean及其子類時,通過getBean()方法返回的不是FactoryBean及其子類本身,而是返回FactoryBean的getObject()方法返回的對象。
如果希望獲取FactoryBean及其子類本身的對象,則在getBean(beanName)方法時顯式地在beanName前加上“&”前綴,如getBean("&car5")。
5、基於註解的配置
5.1、註解類型
@Component------原生註解
衍型註解:
@Repository:標註DAO
@Service:標註service
@Controller:標註控制器
5.2、使用註解配置信息啟動spring容器
(1)spring2.5以後引入了context命名空間,它提供了通過掃描類包以應用註解定義bean:
<context:component-scan base-package="xxxxxxxxxx" resource-pattern="xxxx/*.class">
resource-pattern屬性用於指定在基包中需要掃描的特定包下的類
(2)還有更加強大過濾子標籤
<context:component-scan base-package="xxxxxxxxxx" > <context:include-filter type="xxxx" expression="xxxxxxxxxxxxxxxx"/> <context:exclude-filter type="xxxx" expression="xxxxxxxxxxxxxxxx"/></context:component-scan>
在所有的類型中,aspectj的過濾能力是最強大的。
5.3、自動裝配Bean
(1)@Autowired
@Autowired默認按類型匹配的方式,如果容器中沒有一個匹配的bean,spring容器啟動時將拋出異常,那麼可以使用@Autowired(required=false)進行標註,則不會拋出異常。
使用@Autowired還可以對方法入參直接標註,如果一個方法有多個入參,在默認情況下,spring自動選擇匹配入參類型的bean進行注入。
使用@Autowired標註集合變量,可以將所有匹配該集合元素類型的bean都注入進來,很強大。
使用@Autowired裝配屬性,可以沒有setter方法。
(2)@Qualifiler
如果容器中有一個以上匹配的bean,則可以通過@Qualifiler註解限定bean的名稱。
(3)對標註註解的支持
spring還支持JSR-250定義的@Resource和JSR-330定義的@Inject註解
@Resource要求提供一個bean的名稱屬性,如果屬性為空,則自動採用變量名或者方法名作為bean的名稱。
(4)要點:
如果僅僅使用@Autowired,我們仍然需要顯式地在xml中定義<bean/>節點,spring容器默認禁用註解裝配,啟用的方式是在xml中配置<context:annotation-config/>元素。
但是spring還提供了另一種技巧,使用<context:component-scan/>元素,spring容器就會自動檢測bean,而不需要顯式的定義<bean/>節點。
spring通過@Component、@Repository、@Service、@Controller註解標註類,讓<context:component-scan/>知道哪些類需要註冊為SpringBean。
如果使用了第三方的jar包,且希望自動注入第三方jar包中的類,即使第三方jar包的類中沒有使用註解標註它們,過濾器元素<context:include-filter>可以替換掉基於註解的組件掃描策略,讓<context:component-scan/>自動註冊符合expression表達式的類。
5.4、Bean作用範圍及生命過程方法
(1)@Scope("xxxx")
通過註解配置的Bean和通過xml配置的Bean一樣,默認的作用範圍都是singleton。
spring提供了@Scope註解,作用於類上,註解的參數就和xml中<bean/>的scope屬性的值一樣。
(2)生命過程方法對比
| <bean> | 註解 |
| init-method | @PostConstruct |
| destory-method | @PreDestroy |
區別:註解在類中可以定義多個方法,且方法按順序執行
6、基於java類的配置
6.1、使用java類提供Bean定義信息
(1)普通的POJO只要標註@Configuration註解,就可以為spring容器提供bean定義的信息,每個標註了@Bean的方法都相當於提供一個Bean的定義信息。
(2)@Bean
Bean的類型由@Bean標註的方法的返回值類型決定
Bean的名稱默認和方法名相同,也可以通過@Bean(name="xxx")來顯式指定
可以在@Bean處使用@Scope,標註Bean的使用範圍
(3)@Configuration
由於@Configuration註解類本身已經標註了@Component註解,所以任何標註了@Configurstion的類,都可以使用@Autowired被自動裝配到其他類中。
6.2、使用基於java類的配置信息啟動spring容器
(1)spring提供了一個AnnotationConfigApplicationContect類,它能夠直接通過標註@Configuration註解的類啟動Spring容器。
(2)當有多個配置類時
可以通過AnnotationConfigApplicationContect的register方法一個個註冊,然後再調用refresh方法刷新容器以應用這些註冊的配置類。
也可以通過@Import(xxx.class)註解,將其他配置類全部引入到一個配置類中,這樣僅需要註冊一個配置類即可
(3)通過xml配置類引用@Configuration的配置
<context:component-scanbase-package="......"resource-pattern="配置類名">
(4)在配置類中引用xml配置信息
在@Configuration處使用@ImportResource("classpath:................")來引入xml配置文件
6.3、3種配置方式的比較
| XML | 註解 | java類 |
| Bean的實現類是當前項目開發 | 通過代碼方式控制Bean初始化整體邏輯,適用於實例化Bean比較複雜的場景 |
總結
以上就是本文關於spring在IoC容器中裝配Bean詳解的全部內容,希望對大家有所幫助。感興趣的朋友可以繼續參閱本站:
Spring 3.x中三種Bean配置方式比較詳解
淺談Spring單例Bean與單例模式的區別
Spring配置使用之Bean生命週期詳解
如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!