Spring實戰 | 第一部分 Spring的核心(第二章 裝配bean,第三章 高級裝配)

第二章 裝配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的初始化參數
  • 做爲web應用的上下文參數
  • 做爲環境變量
  • 做爲JVM的系統屬性
  • 在繼承測試類上,使用@ActiveProfiles註解配置。

我所喜歡的一種方式是使用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,包括:

  • 單例(singleton):在整個應用中,只建立bean的一個實例。
  • 原型(prototype):每次注入或者經過spring應用上下文獲取的時候,都會建立一個新的bean實例。
  • 會話(session):在web應用中,爲每一個會話建立一個bean實例。
  • 請求(request):在web應用中,爲每一個請求建立一個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擁有不少特性,包括:

  • 使用bean的ID來引用bean
  • 調用方法和訪問對象的屬性
  • 對值進行算術、關係和邏輯運算
  • 正則表達式匹配
  • 集合操做

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中如何建立和使用切面。

相關文章
相關標籤/搜索