前言:java
當討論依賴注入的時候,咱們一般所討論的是將一個bean引用注入到另外一個bean的屬性或構造器參數中。bean裝配的另一個方面指的是將一個值注入到bean的屬性或者構造器參數中。在沒有學習使用怎麼注入外部值時,咱們正常是直接將值寫死在代碼中。如將專輯的名字裝配到BlankDisc bean的構造器或title屬性中。正則表達式
例如,咱們可能按照這樣的方式來組裝BlankDisc:spring
若是使用XML的話,那麼值也會是硬編碼的:express
若是咱們可能會但願避免硬編碼值,而是想讓這些值在運行時再肯定。爲了實現這些功能,Spring提供了兩種在運行時求值的方式:數組
在Spring中,處理外部值的最簡單方式就是聲明屬性源並經過Spring的Environment來檢索屬性(使用@PropertySource註解和Environment)。例如,程序清單3.7展示了一個基本的Spring配置類,它使用外部的屬性來裝配BlankDisc bean。app
在本例中,@PropertySource引用了類路徑中一個名爲app.properties的文件。它大體會以下所示:dom
這個屬性文件會加載到Spring的Environment中,稍後能夠從這裏檢索屬性。用getProperty()實現的。性能
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處於激活狀態:
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和屬性源的屬性
Spring 3引入了Spring表達式語言(Spring Expression Language,SpEL),它可以以一種強大和簡潔的方式將值裝配到bean屬性和構造器參數中,在這個過程當中所使用的表達式會在運行時計算獲得值。SpEL是相似於OGNL和JSF EL的表達式語言,可以在運行時構建複雜表達式,存取對象屬性、對象方法調用等。全部的SpEL都支持XML和Annotation兩種方式,格式:#{ SpEL expression }
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中如何使用字面量仍是頗有用處的,當組合更爲複雜的表達式時,你早晚會用到它們。
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()}
若是要在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表達式的值上。以下表,概述了這些運算符。
運算符類型 | 運 算 符 |
算術運算 | + 、 - 、 * 、 / 、 % 、^ |
比較運算 | < 、 > 、 == 、 <= 、 >= 、 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全部歌曲的名稱列表: