Spring的運行時值注入是爲了在一些應用場景避免將屬性值硬編碼在配置類中而提供的解決方案,Spring目前提供了幾種方式實現運行時值注入,下面咱們分別來說下java
在Spring中,注入外部屬性值的最簡單方式就是聲明一個外部屬性源並經過Spring的Environment檢索該屬性。示例代碼以下:正則表達式
package com.example.demo.config; import com.example.demo.model.UserBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; @Configuration @PropertySource("classpath:app.properties") public class ValueAutoInputConfig { @Autowired private Environment env; @Bean public UserBean userBean(){ return new UserBean(env.getProperty("user.userBean.name"), env.getProperty("user.userBean.password")); } }
對應的屬性配置文件app.propertiesspring
user.userBean.name=yanqingzhang user.userBean.password=123456
Environment屬性相關方法以下:數組
//獲取指定key對應的屬性值 String getProperty(String key); //獲取指定key對應的屬性值,當獲取的屬性值爲空時返回默認值defaultValue String getProperty(String key, String defaultValue); //獲取指定key對應的屬性值,指定返回的屬性值類型爲type指定的類型 <T> T getProperty(String key, Class<T> type); //獲取指定key對應的屬性值,指定返回的屬性值類型爲type指定的類型,當獲取的屬性值爲null時返回默認值defaultValue <T> T getProperty(String key, Class<T> type, T defaultValue); //獲取key對應的屬性值,默認返回的String對象,若是未指定屬性key則拋出IllegalStateException異常 String getRequiredProperty(String key) throws IllegalStateException; //獲取key對應的屬性值,並基於type指定返回的屬性值類型,若是未指定屬性key則拋出IllegalStateException異常 <T> T getRequiredProperty(String var1, Class<T> type) throws IllegalStateException; //判斷指定屬性key是否存在 boolean containsProperty(String key);
Spring支持將屬性定義到外部的屬性文件中,而後在Spring Bean須要的使用的時候使用佔位符將屬性值注入進來,佔位符的使用形式爲」${}「,咱們下面列舉在XML和@Value註解中使用屬性佔位符app
在使用佔位符以前咱們首先必須配置一個PropertySourcesPlaceholderConfigurer類bean,咱們能夠採用兩種方式配置該Spring Bean一種是在XML配置文件中添加命令空間<context:property-placeholder />,內容以下:dom
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="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.xsd "> <context:property-placeholder /> </beans>
另外一種則是使用@Bean註解在Java配置類中聲明,代碼以下:性能
@Configuration @PropertySource("classpath:app.properties") @ComponentScan(basePackageClasses = {UserBean.class}) public class ValueAutoInputConfig { @Autowired private Environment env; @Bean public PropertySourcesPlaceholderConfigurer placeholderConfigurer(){ return new PropertySourcesPlaceholderConfigurer(); } }
1)在XML配置文件中使用佔位符ui
<bean id="userBean" class="com.jiayun.spring.learn.model.UserBean"> <property name="name" value="${user.userBean.name}" /> <property name="password" value="${user.userBean.password}" /> </bean>
2)在@Value註解中使用屬性佔位符this
@Component public class UserBean { @Value("${user.userBean.name}") private String name; @Value("${user.userBean.password}") private String password; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
解析外部屬性可以將值的處理推遲到運行時,可是它只能根據屬性名稱獲取來自Spring Environment和外部屬性源的屬性配置,下面講述的Spring表達式語言(SpEL)提供更增強大的功能編碼
Spring表達式語言(SpEL)可以以一種很是簡介且強大的方式將運行時外部值裝配到到bean屬性和構造器參數中,它主要有如下幾種使用方式:
1)表示字面值
@Component public class UserBean { @Value("#{'yanqingzhang'}") private String name; @Value("#{123456}") private String password; ...... }
2)引用Bean、屬性和方法
引用Bean
@Service public class UserBeanQuery { @Value("#{userBean}") private UserBean userBean; ...... }
引用Bean屬性
@Service public class UserBeanQuery { @Value("#{userBean.name}") private String userName; public String getUserName(){ System.out.println(userName); return userName; } }
引用方法
@Service public class UserBeanQuery { @Value("#{userBean.getName().toUpperCase()}") private String userName; public String getUserName(){ System.out.println(userName); return userName; } }
爲了不userBean.getName()返回的String對象爲null還能夠這樣寫防止NullPointException,採用如下方式寫執行到getName方法返回null對象時表達式直接返回null再也不執行後面的轉大寫方法toUpperCase
@Service public class UserBeanQuery { @Value("#{userBean.getName()?.toUpperCase()}") private String userName; public String getUserName(){ System.out.println(userName); return userName; } }
3)在表達式中使用類型
若是須要在表達式中訪問類做用域的方法和常量必須得依賴T()這個關鍵的運算符,例如要在SpEL表達式中使用Java的Math類能夠寫成T(java.io.Math),T()關鍵運算符的做用是可讓咱們能夠訪問目標類內部的靜態成員變量和靜態成員方法,固然咱們也能夠將T()運算符結果的Class對象和普通Bean同樣裝配到Bean屬性中
@Service public class UserBeanQuery { @Value("#{T(java.lang.Math).random()*20}") private int age; }
4)SpEL運算符
SpEL提供了許多運算符,幾乎支持全部的算術、比較、邏輯、條件、正則運算,如下運算符均可以應用於SpEL表達式
運算符類型 | 運算符 |
算術運算 | +、-、*、/、%、^ |
比較運算符 | <、>、==、<=、>=、lt、gt、eq、le、ge |
邏輯運算符 | and、or、not、| |
條件運算符 | 三元運算( exp ? value1 : value2)、Evis運算符(exp ?: value) |
正則表達式 | matches |
這裏講解下Evis運算符的使用,例如這樣一個Evis運算符表達式exp ?: value 假如exp是null那麼表達式的計算結果就是value。以下給出在@Value註解上使用示例:
@Service public class UserBeanQuery { @Value("#{userBean.getName() ?: 'defaultName'}") private String userName; public String getUserName(){ System.out.println(userName); return userName; } }
5 )使用正則表達式
@Service public class UserBeanQuery { @Value("#{userBean.email matches '[a-zA-Z0-9_]+@[a-zA-Z_]+\\.com'}") private boolean isTrueEmail; public Boolean isTrueEmail(){ return isTrueEmail; } }
注意UserBean的類中必須實現email屬性的get/set方法
6 - 計算集合
SpEL支持基於索引下標獲取集合和數組的元素,在此基礎上還提供了查詢運算符 」 .?[] 「,他會用來對集合或數組進行過濾獲得集合或者數組的一個子集過濾條件放在中括號[]以內,SpEL還支持其餘兩個運算符」 .^[ ] 「和」 .$[ ]「分別用於在集合中查詢匹配中括號內過濾條件的第一項和最後一項元素,最後SpEL表達式還支持投影運算符」 .![] 「他會從集合中每一個元素中選擇指定屬性放到另一個集合上,這個屬性在中括號[]中指定,如下是在@Value註解中的使用示例