spring學習總結——高級裝配學習四(運行時:值注入、spring表達式)

 

前言:java

  當討論依賴注入的時候,咱們一般所討論的是將一個bean引用注入到另外一個bean的屬性或構造器參數中。bean裝配的另一個方面指的是將一個值注入到bean的屬性或者構造器參數中。在沒有學習使用怎麼注入外部值時,咱們正常是直接將值寫死在代碼中。如將專輯的名字裝配到BlankDisc bean的構造器或title屬性中。正則表達式

例如,咱們可能按照這樣的方式來組裝BlankDisc:spring

若是使用XML的話,那麼值也會是硬編碼的:express

 若是咱們可能會但願避免硬編碼值,而是想讓這些值在運行時再肯定。爲了實現這些功能,Spring提供了兩種在運行時求值的方式:數組

  1. 屬性佔位符(Property placeholder)。
  2. Spring表達式語言(SpEL)

1、注入外部的值

在Spring中,處理外部值的最簡單方式就是聲明屬性源並經過Spring的Environment來檢索屬性(使用@PropertySource註解和Environment)。例如,程序清單3.7展示了一個基本的Spring配置類,它使用外部的屬性來裝配BlankDisc bean。app

在本例中,@PropertySource引用了類路徑中一個名爲app.properties的文件。它大體會以下所示:dom

這個屬性文件會加載到Spring的Environment中,稍後能夠從這裏檢索屬性。用getProperty()實現的。性能

 

一、深刻學習Spring的Environment

1.一、Environment的getProperty()方法有四個重載的變種形式:學習

//獲取屬性值 若是找不到返回null   
String getProperty(String key);  
       
//獲取屬性值,若是找不到返回默認值        
String getProperty(String key, String defaultValue);  
    
//獲取指定類型的屬性值,找不到返回null  
<T> T getProperty(String key, Class<T> targetType);  
  
//獲取指定類型的屬性值,找不到返回默認值  
<T> T getProperty(String key, Class<T> targetType, T defaultValue);  

 1.二、Environment還提供了幾個與屬性相關的方法ui

//獲取屬性值,找不到拋出異常IllegalStateException  
String getRequiredProperty(String key) throws IllegalStateException;  

//檢查一下某個屬性是否存在
boolean containsProperty(String key);

//獲取屬性值爲某個Class類型,找不到返回null,若是類型不兼容將拋ConversionException  
<T> Class<T> getPropertyAsClass(String key, Class<T> targetType);  

除了屬性相關的功能之外,Environment還提供了一些方法來檢查哪些profile處於激活狀態:

  • String[] getActiveProfiles():返回激活profile名稱的數組;
  • String[] getDefaultProfiles():返回默認profile名稱的數組;
  • boolean acceptsProfiles(String... profiles):若是environment支持給定profile的話,就返回true。

 

二、屬性佔位符

  Spring一直支持將屬性定義到外部的屬性的文件中,並使用佔位符值將其插入到Spring bean中。

  佔位符的形式爲使用"${}"包裝的屬性名稱,爲了使用屬性佔位符,咱們必須配置一個PropertyPlaceholderConfigurer或PropertySourcesPlaceholderConfigurer實例,從Spring 3.0開始,推薦使用PropertySourcesPlaceholderConfigurer,由於它可以基於Spring Environment及其屬性源來解析佔位符。

 

一、在基於Java配置中使用屬性佔位符注入屬性

package chapter3.prctice6;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.stereotype.Component;

@Component
public class AppleMobile implements Mobile {
    
    private String color;
    
    private String type;
        
    public AppleMobile(@Value("${mobile.color}") String color, @Value("${mobile.type}") String type) {
        this.color = color;
        this.type = type;
    }
    
    @Bean
    public PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
    
    public void play() {
        System.out.println(color+"-"+type);
    }

}

二、在基於XML配置中使用佔位符注入屬性

<?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"
    xmlns:c="http://www.springframework.org/schema/c"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/jdbc 
        http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd">
    
        <bean id="appleMobile" class="chapter3.prctice6.AppleMobile" 
        c:color="${moble.color}"
        c:type="${mobile.type}">
        </bean>
        <context:property-placeholder/>
</beans>

解析外部屬性可以將值的處理推遲到運行時,它的關注點在於根據名稱解析來自於Spring Environment和屬性源的屬性

 

2、使用Spring表達式語言進行裝配

  Spring 3引入了Spring表達式語言(Spring Expression Language,SpEL),它可以以一種強大和簡潔的方式將值裝配到bean屬性和構造器參數中,在這個過程當中所使用的表達式會在運行時計算獲得值。SpEL是相似於OGNL和JSF EL的表達式語言,可以在運行時構建複雜表達式,存取對象屬性、對象方法調用等。全部的SpEL都支持XML和Annotation兩種方式,格式:#{ SpEL expression }


SpEL擁有不少特性,包括:

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

 

一、SpEL樣例

  須要瞭解的第一件事情就是SpEL表達式要放到「#{ ... }」之中,這與屬性佔位符有些相似,屬性佔位符須要放到「${ ... }」之中。

//字面值表達式
#{1}

//T()表達式會將java.lang.System視爲Java中對應的類型,所以能夠調用其static修飾的currentTimeMillis()方法。
#{T(System).currentTimeMillis()}

//引用其餘的bean或其餘bean的屬性(獲得ID爲sgtPeppers的bean的artist屬性)
#{sgtPeppers.artist}

//經過systemProperties對象引用系統屬性(proerty文件)
#{systemProperties['disc.title']}

  這只是SpEL的幾個基礎樣例。在本章結束以前,你還會看到不少這樣的表達式。可是,在此以前,讓咱們看一下在bean裝配的時候如何使用這些表達式。

  當經過組件掃描建立bean的話,在注入屬性和構造器參數時,咱們可使用@Value註解(必需要經過annotation註冊組件才能夠用)。這與以前看到的屬性佔位符很是相似。不過,在這裏咱們所使用的不是佔位符表達式,而是SpEL表達式。例如,下面的樣例展示了BlankDisc,它會從系統屬性中獲取專輯名稱和藝術家的名字:

  在XML配置中,你能夠將SpEL表達式傳入<property>或<constructor-arg>的value屬性中,或者將其做爲p-命名空間或c-命名空間條目的值。

 

二、表示字面值

使用SpEL來表示整數字面量、浮點數、String值以及Boolean值。

//表示數值1
#{1}

//表示浮點值
#{3.14159}

//表示科學記數法,下面值:98,700
#{9.87E4}

//表示String類型的字面值
#{'Hello'}

//表示Boolean類型的值
#{false}

  在SpEL中使用字面值其實沒有太大的意思,只包含字面值狀況並無太大的用處。SpEL表達式是由更簡單的表達式組成d的。瞭解在SpEL中如何使用字面量仍是頗有用處的,當組合更爲複雜的表達式時,你早晚會用到它們。

三、引用bean、屬性和方法

  SpEL所能作的另一件基礎的事情就是經過ID引用其餘的bean。例如,你可使用SpEL將一個bean裝配到另一個bean的屬性中,此時要使用bean ID做爲SpEL表達式(在本例中,也就是sgtPeppers):

//引用ID爲sgtPeppers的Bean
#{sgtPeppers}

//表達式中引用sgtPeppers的artist屬性
#{sgtPeppers.artist}

//表達式中調用bean上的方法:調用bean的selectArtist()方法
#{artistSelector.selectArtist()}

//對於被調用方法的返回值來講,咱們一樣能夠調用它的方法。例如,若是selectArtist()
//方法返回的是一個String,那麼能夠調用toUpperCase()將整個藝術家的名字改成大寫
//字母形式:

#{artistSelector.selectArtist().toUpperCase()}

//使用了「?.」運算符。這個運算符可以在訪問它右邊的內容以前,確保它所對應的元素不是
//null。因此,若是selectArtist()的返回值是null的話,那麼SpEL將不會調用toUpperCase()
//方法。表達式的返回值會是null。(避免出現NullPointerException)

#{artistSelector.selectArtist()?.toUpperCase()}

 

四、在表達式中使用類型(Class對象)

  若是要在SpEL中訪問類做用域的方法和常量的話,要依賴T()這個關鍵的運算符。例如,爲了在SpEL中表達Java的Math類,須要按照以下的方式使用T()運算符:

  

//這裏所示的T()運算符的結果會是一個Class對象表明了java.lang.Math。
#{T(java.lang.Math)}

//T()運算符的真正價值在於它可以訪問目標類型的靜態方法和常量。

//獲取類的靜態屬性
#{T(java.lang.Math).PI}

//獲取類的靜態方法:計算獲得一個0到1之間的隨機數
#{T(java.lang.Math).random()}

  這裏所示的T()運算符的結果會是一個Class對象,T()運算符的真正價值在於它可以訪問目標類型的靜態方法和常量。與之相似,咱們能夠調用T()運算符所獲得類型的靜態方法。咱們已經看到了經過T()調用System.currentTimeMillis()。

 

五、SpEL運算符

  SpEL提供了多個運算符,這些運算符能夠用在SpEL表達式的值上。以下表,概述了這些運算符。

運算符類型 運 算 符
算術運算 + 、 - 、 * 、 / 、 % 、^
比較運算 < 、 > 、 == 、 <= 、 >= 、 lt 、 gt 、 eq 、 le 、 ge
邏輯運算

and 、 or 、 not 、 │

條件運算  ?: (ternary) 、 ?: (Elvis)
正則表達式 matches

 

 

//這裏是一個類的部分屬性代碼

    @Value("#{1 == 1}") //true
    private boolean testEqual;
 
    @Value("#{1 != 1}") //false
    private boolean testNotEqual;
 
    @Value("#{1 < 1}") //false
    private boolean testLessThan;
 
    @Value("#{1 <= 1}") //true
    private boolean testLessThanOrEqual;
 
    @Value("#{1 > 1}") //false
    private boolean testGreaterThan;
 
    @Value("#{1 >= 1}") //true
    private boolean testGreaterThanOrEqual;
 
    //Logical operators , numberBean.no == 999
 
    @Value("#{numberBean.no == 999 and numberBean.no < 900}") //false
    private boolean testAnd;
 
    @Value("#{numberBean.no == 999 or numberBean.no < 900}") //true
    private boolean testOr;
 
    @Value("#{!(numberBean.no == 999)}") //false
    private boolean testNot;
 
    //Mathematical operators
 
    @Value("#{1 + 1}") //2.0
    private double testAdd;
 
    @Value("#{'1' + '@' + '1'}") //1@1
    private String testAddString;
 
    @Value("#{1 - 1}") //0.0
    private double testSubtraction;
 
    @Value("#{1 * 1}") //1.0
    private double testMultiplication;
 
    @Value("#{10 / 2}") //5.0
    private double testDivision;
 
    @Value("#{10 % 10}") //0.0
    private double testModulus ;
 
    @Value("#{2 ^ 2}") //4.0
    private double testExponentialPower;

//-------------------------結果:---------------

    testEqual=true, 
    testNotEqual=false, 
    testLessThan=false, 
    testLessThanOrEqual=true, 
    testGreaterThan=false, 
    testGreaterThanOrEqual=true, 
    testAnd=false, 
    testOr=true, 
    testNot=false, 
    testAdd=2.0, 
    testAddString=1@1, 
    testSubtraction=0.0, 
    testMultiplication=1.0, 
    testDivision=5.0, 
    testModulus=0.0, 
    testExponentialPower=4.0

 

六、計算正則表達式

  當處理文本時,有時檢查文本是否匹配某種模式是很是有用的。SpEL經過matches運算符支持表達式中的模式匹配。matches運算符對String類型的文本(做爲左邊參數)應用正則表達式(做爲右邊參數)。matches的運算結果會返回一個Boolean類型的值:若是與正則表達式相匹配,則返回true;不然返回false。

七、計算集合

   一、SpEL中最使人驚奇的一些技巧是與集合和數組相關的。最簡單的事情可能就是引用列表中的一個元素了:

 

   二、爲了讓這個表達式更豐富一些,假設咱們要從jukebox中隨機選擇一首歌:

  三、它還能夠從String中獲取一個字符。下標基於零開始,也就結果爲"s",以下:

 

  四、SpEL還提供了查詢運算符(  .?[ ]   ),它會用來對集合進行過濾,獲得集合的一個子集。假設你但願獲得jukebox中artist屬性爲Aerosmith的全部歌曲。

以看到,選擇運算符在它的方括號中接受另外一個表達式。當SpEL迭代歌曲列表的時候,會對歌曲集合中的每個條目計算這個表達式。若是表達式的計算結果爲true的話,那麼條目會放到新的集合中。不然的話,它就不會放到新集合中。

  五、SpEL還提供了另外兩個查詢運算符:「.^[ ]」和「.$[ ]」,它們分別用來在集合中查詢第一個匹配項和最後一個匹配項。

  六、SpEL還提供了投影運算符(.![ ]),它會從集合的每一個成員中選擇特定的屬性放到另一個集合中。做爲樣例,假設咱們不想要歌曲對象的集合,而是全部歌曲名稱的集合。以下的表達式會將title屬性投影到一個新的String類型的集合中:

 

實際上,投影操做能夠與其餘任意的SpEL運算符一塊兒使用。好比,咱們可使用以下的表達式得到Aerosmith全部歌曲的名稱列表:

相關文章
相關標籤/搜索