第二章 裝配bean java
聲明beanweb
構造器注入和setter方法注入正則表達式
裝配beanspring
控制bean的建立和銷燬express
1、Spring配置的可選方案編程
主要的裝配機制:安全
一、在xml中進行顯式配置session
二、在Java中進行顯式配置app
三、隱式的bean發現機制和自動裝配框架
儘量的用自動配置的機制。
2、自動化裝配bean
一、建立可被發現的bean
Spring從兩個角度來實現自動化裝配:
組件掃描:spring會自動發現應用上下文中所建立的bean。
自動裝配:spring自動知足bean之間的依賴。
組件掃描和自動裝配組合在一塊兒就能發揮出強大的威力,它們可以將你的顯示裝配降到最低。
① 由於使用了@Component註解,因此spring會爲你把事情處理穩當。
② @ComponentScan註解啓用了組件掃描
③ 經過xml啓用組件掃描
二、爲組件掃描的bean命名
強烈推薦@Component命名
三、設置組件掃描的基礎包
@Configuration @ComponentScan("soundsystem") public class CDPlayConfig{ }
設置組件掃描的基礎包
@Configuration @ComponentScan(basePackageClasses={CDPlayer.class,DVDPlayer.class}) public class CDPlayerConfig{ }
四、經過爲bean添加註解實現自動裝配
@Autowired
將required屬性設置爲false時,Spring會嘗試執行自動裝配,可是若是沒有匹配的bean的話,spring將會讓這個bean處於未裝配的狀態。可是此時要進行null值檢查,不然會出現空指針異常。
@Inject註解來源於Java依賴注入規範
spring同時支持@Autowired和@Inject。
五、驗證自動裝配
3、經過Java代碼裝配bean
當要將第三方庫中的組件裝配到程序中時,這種狀況下是沒辦法加@Component和@Autowired註解的,所以不能自動化裝配。
顯式配置時,JavaConfig是更好的方案,JavaConfig是配置代碼,JavaConfig要放到單獨的包中。
一、建立配置類
建立JavaConfig類的關鍵在於爲其添加@Configuration註解,@Configuration註解代表這個類是一個配置類,該類應該包含在Spring應用上下文中如何建立bean的細節。
二、聲明簡單的bean
三、藉助JavaConfig實現注入
@Bean註解代表這個方法會建立一個bean實例並將其註冊到Spring應用上下文中。
四、經過xml裝配bean
① 建立XML配置規範
② 聲明一個簡單的bean
③ 藉助構造器注入初始化bean
④ 設置屬性
推薦構造器注入
五、導入和混合配置
① 在JavaConfig中引用XML配置
② 在XML配置中引用JavaConfig
六、小結
Spring框架的核心是Spring容器。容器負責管理應用中組件的生命週期,它會建立這些組件並保證他們的依賴可以獲得知足,這樣的話,組件才能完成預約的任務。在本章中,咱們看到了在Spring中裝配bean的三種主要方式,這些技術描述了Spring應用中的組件以及這些組件之間的關係。
儘量使用自動化配置,以免顯示配置所帶來的維護成本。可是,若是你確實須要顯示配置Spring的話,應該優先選擇基於Java的配置,它比基於CML的配置更增強大、類型安全而且易於重構。
第三章 高級裝配
Spring profile
條件化的bean聲明
自動裝配與歧義性
bean的做用域
Spring表達式語言
1、環境與profile
一、spring中的profile是什麼?
profile能夠理解爲咱們在Spring容器中所定義的Bean的邏輯組名稱,只有當這些Profile被激活的時候,纔會將Profile中所對應的Bean註冊到Spring容器中。舉個更具體的例子,咱們以前定義bean的時候,當spring容器以啓動的時候,就會一股腦的所有加載這些信息完成對bean的建立;而使用profile後,它會將bean的定義進行更細粒度的劃分,將這些定義的bean劃分爲幾個不一樣的組,當spring容器加載信息的時候,首先查找激活的profile,而後只會去加載被激活的組中所定義的bean信息,而不被激活的profile中所定義的bean是不會加載用於建立bean的。
二、爲何要是用profile
由於須要啥就加載啥,不須要的就不用了加載了
三、配置spring profile
在3.1版本中,spring引入了bean profile的功能。要使用profile,首先要將全部不一樣的bean定義整理到一個或多個profile中,將應用部署到每一個環境中,確保對應的profile處於激活(active)的狀態。
在java配置中,可使用@profile註解指定某個bean屬於哪個profile。
四、激活profile
spring在肯定哪一個profile處於激活狀態時,須要依賴兩個獨立的屬性:spring.profiles.active和spring.profiles.default。若是配置了spring.profiles.active屬性的話,那麼它的值就會用來肯定哪一個profile是激活的。可是若是沒有配置spring.profiles.active,那spring將會查找spring.profiles.default的值。
有兩種方式來設置這兩個屬性:
我所喜歡的一種方式是使用DispatcherServlet的參數將spring.profiles.default設置爲開發環境的profile,我會在servlet上下文中進行設置(爲了兼顧到ContextLoaderListener)。例如,在web應用中,設置spring.profiles.default的web.xml文件會以下所示:
在web應用的web.xml文件中設置默認的profile
<?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"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/root-context.xml</param-value> </context-param> <context-param> <param-name>spring.profiles.default</param-name><!--爲上下文設置默認的profile--> <param-value>dev</param-value> </context-param> <listen> <listen-class> org.springframework.web.context.ContextLoaderListenr </listen-class> </listen> <servlet> <servlet-name>appServlet</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <init-param> <param-name>spring.profiles.default</param-name><!--爲servlet設置默認的profile--> <param-value>dev</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </beans>
按照這種方式設置spring.profiles.default,全部開發人員都能從版本控制軟件中得到應用程序源碼,並使用開發環境的設置運行代碼,而不須要額外的配置。
系統會優先使用spring.profiles.active中所設置的profile。
spring提供了@ActiveProfiles註解,咱們可使用它來指定運行測試時要激活哪一個profile。在集成測試時,一般想要激活的是開發環境的profile。
在條件化建立bean的時候,spring的profile機制是一種很棒的方法,這裏的條件要基於哪一個profile處於激活狀態來判斷。
2、條件化的bean
spring4引入了一個新的@Conditional註解,它能夠用到帶有@Bean註解的方法上。若是給定的條件計算結果爲true,就會建立這個bean,否者,這個bean就會被忽略。
例如,假設有一個名爲MagicBean的類,咱們但願只有設置了magic環境屬性的時候,Spring纔會實例化這個類。若是環境中沒有這個屬性,那麼MagicBean將會被忽略。
條件化的建立bean:
@Bean @Conditional(MagicExistsCondition.class)//條件化地建立bean public MagicBean magicBean(){ return new MagicBean(); }
能夠看到,@Conditional中給定了一個Class,它指明瞭條件,在本例中,也就是MagicExistsCondition。@Conditional將會經過Condition接口進行條件對比:
public interface Condition{ boolean matches(ConditionContext ctxt,AnnoatedTypeMetadata metadata); }
設置給@Conditional的類能夠是任意實現了Condition接口的類。能夠看出,這個接口實現起來很簡單直接,只需提供matches()方法的實現便可。若是matches()方法返回true,那麼就會建立帶有@Conditional註解的bean。若是matches()方法返回false,將不會建立bean。
在condition中檢查是否存在magic屬性
public class MagicExistsCondition implements Condition{ public boolean matches(ConditionContext ctxt,AnnoatedTypeMetadata metadata){ Environment env = context.getEnvironment(); return env.containsProperty("magic");//檢查magic屬性 } }
在上面的程序中,matches()方法很簡單但功能很強大。它經過給定的ConditionContext對象進而獲得Environment對象,並使用這個對象檢查環境中是否存在名爲magic的環境屬性。若是返回true,就表示@Conditional註解上引用MagicExistsCondition的bean都會被建立。
ConditionContext是一個接口,大體以下所示:
public interface ConditionContext{ //檢查bean定義 BeanDefinitionRegistry getRegistry(); //檢查bean是否存在,檢查bean的屬性 ConfigurableListableBeanFactory getBeanFactory(); //檢查環境變量是否存在以及它的值是什麼 Environment getEnvironment(); //讀取ResourceLoader加載的資源 ResourceLoader getResourceLoader(); //加載並檢查類是否存在 ClassLoader getClassLoader(); }
AnnotatedTypeMetadata則可以讓咱們檢查帶有@bean註解的方法上是否還有其餘的註解。像ConditionContext同樣,AnnotatedTypeMetadata也是一個接口。
public interface AnnotatedTypeMetadata{ //藉助isAnnotated()方法,判斷帶有@bean註解的方法是否還有其餘特定的註解。 boolean isAnnotated(String annotationType); //檢查@bean註解的方法上其餘註解的屬性 Map<String,Object> getAnnotationAttributes(String annotationType); Map<String,Object> getAnnotationAttributes(String annotationType,boolean classValuesAsString); MultiValueMap<String,Object> getAllAnnotationAttributes(String annotationType); MultiValueMap<String,Object> getAllAnnotationAttributes(String annotationType,boolean classValuesAsString); }
從spring4開始,@profile註解進行了重構,使其基於@Conditional和Condition實現。來看一下,spring4中@profile是如何實現的。
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE,ElementType.METHOD}) @Documented @Conditional(ProfileCondition.class) public @interface Profile{ String[] value(); }
@Profile自己也使用了@Condition註解,而且引用ProfileCondition做爲Condition實現。以下所示,ProfileCondition實現了Condition接口,而且考慮到了ConditionContext和AnnotatedTypeMatadata中的多個元素。
ProfileCondition檢查某個bean profile是否可用:
class ProfileCondition implements Condition{ public boolean matches(ConditionContext context,AnnotatedTypeMetadata){ if(context.getEnvironment()!=null){ MultiValueMap<String,Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName()); if(attrs!=null){ for(Object value:attrs.get("value")){ if(context.getEnvironment().acceptsProfiles(String[] value)){ return true; } } return false; } } return true; } }
咱們能夠看到,ProfileCondition經過AnnotatedTypeMetadata獲得了用於@Profile註解的全部屬性,藉助這些信息,它明確的檢查value屬性,該屬性包含了bean的Profile名稱,而後,它經過ConditionContext獲得的Environment來檢查[藉助accpetsProfiles()方法]該profile是否處於激活狀態。
3、處理自動裝配的歧義性
若是不只有一個bean可以匹配結果的話,這種歧義性會阻礙spring自動裝配屬性、構造器參數或方法參數。
若是三個實現類均使用了@Component註解,在組件掃描的時候,可以發現他們並將其建立爲Spring應用上下文裏面的bean,而後,當spring自動裝配的時候,它並無惟1、無歧義的可選值。此時,spring會拋出異常。
就算歧義性是個問題,但實際開發中不多碰見,給定的類型只有一個實現類就行了嘛,自動裝配可以很好地運行。
可是,當歧義性確實發生時,spring提供了多種可選方案來解決這樣的問題。你能夠將可選bean中的某一個設爲首選(primary)的bean,或者使用限定符(qualifier)來幫助spring將可選的bean的範圍縮小到只有一個bean。
一、標識首選的bean
在聲明bean的時候,經過將其中一個可選的bean設置爲首選(primary)bean可以避免自動裝配時的歧義性。當遇到歧義性的時候,Spring將會使用首選的bean,而不是其餘可選的bean。
@Bean @Primary public class IceCrean implements Dessert{ }
若是XML配置bean的話,一樣能夠實現此功能。<bean>元素有一個primary屬性來指定首選的bean。
二、限定自動裝配的bean
@Autowired @Qualifier("iceCream") public void setDessert(Dessert dessert){ this.dessert = dessert; }
@Qualifier註解所設置的參數就是想要注入對的bean的ID。全部使用@Component註解聲明的類都會建立bean,而且bean的ID爲首字母變爲小寫的類名。所以,@Qualifier(「iceCream」)指向的是組件掃描時鎖建立的bean,而且這個bean時IceCream類的實例。
@Component--把這些類歸入進spring容器中管理。
建立自定義的限定符
咱們能夠爲bean設置本身的限定符,而不是依賴將beanID做爲限定符。在這裏須要加上@Qualifier,與@Component配合使用
@Component @Qualifier("sexy") public class IceCream implements Dessert{...}
在這種狀況下,sexy限定符分配給了IceCreambean。由於它沒有耦合類名,所以你能夠隨意重構IceCream的類名,而沒必要擔憂會破壞自動裝配。在注入的地方,引用sexy限定符便可:
@Component @Qualifier("sexy") public class setDessert(Dessert dessert){ this.dessert = dessert; }
當配置顯式bean的時候,@Qualifier也能夠與@bean註解一塊兒使用:
@Bean @Qualifier("sexy") public Dessert iceCream{ return new IceCream(); }
當使用@Qualifier值時,最佳實踐是爲bean選擇特徵性或描述性的術語,而不是使用隨便的名字。
經過聲明自定義的限定符註解,咱們能夠同時使用多個限定符,不會再有Java編譯器的限制或錯誤。與此同時,相對於使用原始的@Qualifier並藉助string類型來指定限定符,自定義的註解更爲安全。
爲了建立自定義的條件化註解,咱們建立了一個新的註解並在這個註解上添加了@Conditional。爲了建立自定義的限定符註解,咱們建立了一個新的註解並在這個註解上添加了@Qualifier。這種技術能夠用到不少spring註解中,從而可以將它們組合在一塊兒造成特定目標的自定義註解。
如今咱們來看一下如何在不一樣的做用域中聲明bean。
4、bean的做用域
默認狀況下,spring應用上下文中全部bean都是做爲以單例(singleton)的形式建立的。也就是說,無論給定的一個bean被注入到其它bean多少次,每次所注入的都是同一個實例。
spring定義了多種做用域,能夠基於這些做用域建立bean,包括:
單例是默認的做用域,對於易變的類型,這並不合適。若是選擇其餘的做用域,要使用@Scope註解,它能夠與@Component或@bean一塊兒使用。
@Component @Scope(ConfigurableBeanFacory.SCOPE_PROTOTYPE) public class Notepad{ }
使用ConfigurableBeanFacory類的SCOPE_PROTOTYPE常量設置了原型做用域。你固然也可使用@Scope(「prototype」),可是使用SCOPE_PROTOTYPE常量更加安全而且不易出錯。
一樣也可使用XML來配置bean:
<bean id="notepad" class="com.oschina.Notepad" scope="prototype"></bean>
無論你使用哪一種方式來聲明原型做用域,每次注入或從spring應用上下文中檢索該bean的時候,都會建立新的實例。這樣所致使的結果就是每次操做都能獲得本身的notepad實例。
一、使用會話和請求做用域
在web應用中,若是可以實例化在會話和請求範圍內共享的bean,那將時很是有價值的事情。例如,在典型的電子商務應用中,可能會有一個bean表明用戶的購物車。若是購物車是單例的,那麼將會致使全部的用戶都會向同一個購物車中添加商品。另外一方面,若是購物車是原型做用域的,那麼在應用中某一個地方網購物車中添加物品,在應用的另一個地方可能就不可用了,由於這裏注入的是另外一個原型做用域的購物車。
就購物車bean來講,會話做用域是最爲合適的,由於它與給定的用戶關聯性最大。要指定會話做用域,咱們可使用@Scope註解,它的使用方式與指定原型做用域是相同的:
@Component @Scope(value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopeProxyMode.INTERFACES) public ShoppingCart cart(){ }
咱們將value設置成了WebApplicationContext中的SCOPE_SESSION常量,這回告訴spring爲web應用中每個會話建立一個ShoppingCart。這會建立多個ShoppingCart的bean實例,可是對於給定的會話只是建立了一個實例,在當前會話中,這個bean至關於單例的。
要注意的是,@Scope同時還有一個proxyMode屬性,它被設置成了ScopeProxyMode.INTERFACES。這個屬性解決了將會話或請求做用域的bean注入到單例bean中所遇到的問題。在描述proxyMode屬性以前,咱們先來看一下ProxyMode所解決的場景。
假設咱們將shoppingCart bean注入到單例StoreService bean的setter方法中,以下所示:
@Component public class StoreService{ @Autowired public void setShoppingCart(ShoppingCart shoppingCart){ this.shoppingCart=shoppingCart; } ... }
@Autowired是用在Javabean中的註解,經過byType形式,用來給指定的字段或方法注入所需的外部資源。
先看一下bean實例化和@Autowired裝配過程:
一、一切都是從bean工廠的getBean方法開始的,一旦該方法調用總會返回一個bean實例 。
二、實例化和裝配過程當中會屢次遞歸調用getBean方法來解決類之間的依賴。
三、@Autowired是根據類型來查找和裝配的,可是咱們設置了<beans default-autowired="byName"/>後會影響最終的類型匹配查找。由於在前面有根據BeanDefinition的autowire類型設置PropertyValue值的一步,其中會有新實例的建立和註冊。就是那個autowireByName方法
由於StoreService是一個單例bean,會在spring應用上下文加載的時候建立,當它建立的時候,spring會試圖將ShoppingCart bean注入到setShoppingCart()方法中。 但ShoppingCart bean是會話做用域的,此時並不存在。直到某個用戶進入系統,建立了會話以後,纔會出現ShoppingCart實例。
另外,系統中將會有多個ShoppingCart實例,每一個用戶一個,咱們並不想讓spring注入某個固定的ShoppingCart實例到storeService中。咱們但願的是當StoreService處理購物車功能時,它所使用的ShoppingCart實例剛好是當前會話所對應的那一個。
二、在xml中聲明做用域代理
若是你須要使用XML來聲明會話或請求做用域的bean,那麼就不能使用@Scope註解及其ProxyMode屬性了。<bean>元素的scope屬性可以設置bean的做用域,可是該怎樣指定代理模式呢?
要設置代理模式,咱們須要使用Spring aop命名空間的一個新元素:
<bean id="cart" class="com.oschina.ShoppingCart" scope="session"> <aop:scoped-proxy/> </bean>
<aop:scoped-proxy/>是與@Scope註解的ProxyMode屬性功能相同的Spring XML配置元素。它會告訴spring爲bean建立一個做用域代理。默認狀況下,它會使用CGLib建立目標類的代理。可是咱們也能夠將proxy-target-class屬性設置爲false,進而要求它生成基於接口的代理:
<bean id="cart" class="com.oschina.ShoppingCart" scope="session"> <aop:scoped-proxy proxy-target-class="false" /> </bean>
爲了使用<aop:scoped-proxy>元素,咱們必須在XML配置中聲明spring的aop命名空間:
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> ... </beans>
在第4章中,咱們使用spring和切面編程的時候,會討論spring aop命名空間的更多知識,如今咱們來看一下spring高級配置的另一個可選方案:spring表達式語言(spring expression language)。
5、運行時值注入
一、注入外部的值
在Spring中,處理外部值最賤的方式就是聲明屬性源並經過spring的environment來檢索屬性。
package com.oschina @Configuration //聲明屬性源 @PropertySource("classpath:/com/oschina/app.properties") public class ExpressiveConfig{ @Autowired Environment env; @Bean public BlankDisc disc(){ //檢索屬性值 return new BlankDisc(env.getProperty("disc.title"),env.getProperty("disc.artist")); } }
深刻學習spring的environment
直接從environment中檢索屬性是很是方便的,尤爲是在Java配置中裝配bean的時候。可是spring也提供了經過佔位符裝配屬性的方法,這些佔位符的值會來源於一個屬性源。
解析佔位符
在spring裝配中,佔位符的形式爲使用「${...}」包裝的屬性名稱。
<bean id="sgtPeppers" class="soundsystem.BlankDisc" c:_title="${disc.title}" c:_artist="${disc.artist} />"
二、使用spring表達式語言進行裝配
spring3引入了spring表達式語言(spring expression language ,SpEL),它可以以一種強大和簡潔的方式將值裝配到bean屬性和構造器參數中,在這個過程當中使用的表達式會在運行時計算的獲得值,使用SpEL,你能夠實現超乎想象的裝配效果,這是使用其餘的裝配技術難以作到的。
SpEL擁有不少特性,包括:
SpEL可以用在依賴注入之外的其餘地方,例如,spring Security支持使用SpEL表達式定義安全限制規則。另外,若是你在spring MVC應用中使用Thymeleaf模板做爲視圖的話,那麼這些模板可使用SpEL表達式引用模板數據。
SpEL樣例
SpEL是一種很是靈活的表達式語言,因此本書中不可能面面俱到的介紹它的各類用法。可是咱們能夠展現幾個基本的例子,這些例子會激發你的靈感,有助於編寫本身的表達式。
SpEL表達式使用"#{...}",這與屬性佔位符有些相似,屬性佔位符是"${...}"。
除去"#{...}"標記以後,剩下的就是SpEL表達式體了,也就是一個數字常量。這個表達式的計算結果就是數字1,這恐怕不會讓你感到絲毫驚訝。
#{T(System).currentTimeMillis()}
它的最終結果是計算表達式的那一刻的當前時間的毫秒數。T()表達式會將java.lang.System視爲Java中對應的類型,所以能夠調用其static修飾的currentTimeMillis()方法。
SpEL表達式也能夠應用其餘的bean或其餘bean的屬性。例如,以下的表達式會計算獲得ID爲sgtPeppers的bean的artist屬性:
#{sgtPeppers.artist}
咱們還能夠經過systemProperties對象引用系統屬性:
#{systemProperties['disc.title']}
這只是SpEL的幾個基礎樣例。
若是經過組件掃描建立bean的話,在注入屬性和構造器參數時,咱們可使用@Value註解,這與以前看到的屬性佔位符很是類似。不過,在這裏咱們所使用的不是佔位符表達式,而是SpEL表達式。例如,下面的樣例展現了BlankDisc,它會從系統屬性中獲取專輯名稱和藝術家的名字:
public BlankDisc(@Value{'#systemProperties['disc.title']'} string title, @Value{'#systemProperties['disc.artist']'} string artist){ this.title = title; this.artist=artist; }
在XML配置中,你能夠將SpEL表達式傳入<property>或<constructor-arg>的value屬性中,或者將其做爲p-命名空間或c-命名空間條目的值。例如,在以下BlankDisc bean的XML聲明中,構造器參數就是經過SpEL表達式設置的:
<bean id="sgtPeppers" class="soundsystem.BlankDisc" c:title="#systemProperties['disc.title']" c:_artist="#[systemProperties['disc.artist']]">
如今咱們來學一下SpEL所支持的基礎表達式:
表示字面值
實際上能夠用來表示浮點值、string值以及Boolean值。
下面的SpEL表達式樣例所表示的就是浮點數:
#{3.141592657}
....
SpEL所能作到的另一件基礎的事情就是經過ID引用其餘的bean。例如,你可使用SpEL將一個bean裝配到另外一個bean的屬性中,此時要是用bean ID做爲SpEL表達式
SpEL運算符
例子:#{2*T(java.lang.Math).PI*circle.radius}
這不只是使用SpEL中乘法運算符的絕佳樣例,它也爲你展現瞭如何將簡單的表達式組合爲更爲複雜得表達式。
SpEL還提供了三元運算符
6、小結
咱們在本章介紹了許多背景知識,在第二章所介紹的基本bean裝配基礎之上,又學習了一些強大的高級裝配技巧。
首先,咱們學習了spring profile,它解決了spring bean要跨各類部署環境的通用問題。在運行時,經過將環境相關的bean與當前激活的profile進行匹配,spring可以讓相同的部署單元跨多種環境運行,而不須要進行從新構建。
Profile bean是在運行時條件化建立bean的一種方式,可是spring4提供了一種更爲通用的方式,經過這種方式能可以聲明某些bean的建立與否要依賴於給定條件的輸出結果。結合使用@Conditional註解和Spring Condition接口的實現,可以爲開發人員提供一種強大和靈活的機制,實現條件化的建立bean。
咱們還看了兩種解決自動裝配歧義性的方法:首選bean以及限定符。儘可能將某個bean設置爲首選bean是很簡單的,單這種方式也有其侷限性,因此咱們討論瞭如何將一組可選的自動裝配bean,藉助限定符將其範圍縮小到只有一個符合條件的bean。除吃以外,咱們還看到了如何建立自定義的限定符註解,這些限定符描述了bean的特性。
儘管大多數的spring bean都是單例的方式建立的,但有的時候其它的建立策略更爲合適。spring可以讓bean以單例、原型、請求做用域或會話做用域的方式來建立。在聲明請求做用域或會話做用域的bean的時候,咱們還學習瞭如何建立做用域代理,它分爲基於類的代理和基於接口的代理兩種方式。
最後咱們還學習了spring表達式語言,他可以在運行時計算要注入到bean屬性中的值。
對於bean裝配,咱們已經掌握了紮實的基礎知識,如今咱們將注意力轉向面向切面編程(AOP)。依賴注入可以將組建及其協做的其餘組件解耦,與之相似,AOP有助於將應用組件與跨多個組件的任務進行解耦。在下一章,咱們將學習在spring中如何建立和使用切面。