Spring提供了2種方式在運行時注入值:java
通常狀況下,咱們會將一些值放到配置文件中,等程序運行時再把值注入到一些字段上。git
假如,咱們有一個test.properties配置文件,內容以下:github
book.author=wangyunfei
book.name=spring boot
author.age=30
複製代碼
如今咱們但願在程序運行時,把這個值分別賦值給字段bookAuthor和bookName,那麼該如何實現呢?spring
首先,新建配置類ExpressiveConfig以下:express
package chapter03.el;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
@Configuration
@ComponentScan
@PropertySource("classpath:chapter03/el/test.properties")
public class ExpressiveConfig {
@Autowired
private Environment environment;
public void outputResource() {
System.out.println("book.name:" + environment.getProperty("book.name"));
System.out.println("book.author:" + environment.getProperty("book.author"));
}
}
複製代碼
這裏咱們使用@PropertySource註解引用了test.properties配置文件,這個文件的位置位於chapter03.el包下。微信
這個屬性文件會加載到Spring的Environment中,而後咱們就能夠調用getProperty()方法獲取到屬性值。dom
新建Main類,在其main()方法中添加以下測試代碼:maven
package chapter03.el;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ExpressiveConfig.class);
ExpressiveConfig expressiveConfig = context.getBean(ExpressiveConfig.class);
expressiveConfig.outputResource();
context.close();
}
}
複製代碼
運行代碼,發現拋出java.io.FileNotFoundException
異常,以下所示:測試
從報錯信息能夠看出, 這是提示找不到chapter03/el/test.properties這個文件,這是爲何呢?ui
帶着這個疑問,咱們看下target目錄下編譯後的代碼,以下所示:
從圖中能夠看出,咱們新建的test.properties和test.txt文件並無被編譯到target目錄下,因此纔會拋出異常。
這是由於,咱們新建文件的位置放在chapter03.el包下,而IDEA默認是不會把這些文件自動複製到target目錄下的,但咱們能夠在pom.xml中添加以下配置來解決該問題:
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.txt</include>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</build>
複製代碼
這裏咱們指定了txt和properties文件,若是須要,能夠繼續添加<include>
標籤指定xml等文件。
再次運行測試代碼,輸出日誌以下所示:
book.name:spring boot
book.author:wangyunfei
此時target目錄下已經包含了咱們新建的2個文件:
若是指定的屬性值不存在,getProperty()會返回null,以下所示:
String workCity = environment.getProperty("author.workcity");
System.out.println("author.workcity:" + workCity);
複製代碼
輸出結果:
author.workcity:null
getProperty()還提供了1個重載,當指定的屬性值不存在時,能夠指定默認值:
String workCity = environment.getProperty("author.workcity", "上海");
System.out.println("author.workcity:" + workCity);
複製代碼
輸出結果:
author.workcity:上海
若是但願屬性值必須存在,可使用getRequiredProperty()方法,當屬性值不存在時,會拋出java.lang.IllegalStateException
異常:
String workCity = environment.getRequiredProperty("author.workcity");
System.out.println("author.workcity:" + workCity);
複製代碼
getProperty()還提供了1個重載,能夠指定返回值的類型,好比咱們想返回Integer類型:
Integer authorAge = environment.getProperty("author.age", Integer.class);
System.out.println("author.age:" + authorAge);
複製代碼
輸出結果:
author.age:30
getProperty()還提供了1個重載,當指定的屬性值不存在時,不只能夠指定默認值,還能夠指定返回值類型:
boolean isMan = environment.getProperty("author.isMan", Boolean.class, true);
System.out.println("author.isMan:" + isMan);
複製代碼
輸出結果:
author.isMan:true
除了使用Environment獲取外部的屬性值,咱們還可使用屬性佔位符來獲取。
在Spring裝配中,佔位符的形式爲使用「${......}」包裝的屬性名稱。
新建Book類以下:
package chapter03.el;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class Book {
@Value("${book.name}")
private String bookName;
@Value("${book.author}")
private String bookAuthor;
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getBookAuthor() {
return bookAuthor;
}
public void setBookAuthor(String bookAuthor) {
this.bookAuthor = bookAuthor;
}
}
複製代碼
能夠發現,咱們在字段上添加了@Value註解,參數傳的值就是屬性佔位符,用來獲取屬性文件中指定的屬性值。
而後,在ExpressiveConfig配置類中添加以下代碼:
@Autowired
private Book book;
public void outputResource() {
System.out.println("book.name:" + book.getBookName());
System.out.println("book.author:" + book.getBookAuthor());
}
複製代碼
輸出結果:
book.name:spring boot
book.author:wangyunfei
Spring表達式語言(Spring Expression Language,SpEL)是一種很是靈活的表達式語言,可以以一種強大和簡潔的方式將值裝配到bean屬性或者構造器參數中,在這個過程當中所使用的的表達式會在運行時計算值。
SpEL表達式要放到「#{......}」之中,而以前講到的屬性佔位符是放到「${......}」之中。
接下來,咱們分場景來看下Spring表達式語言的使用方法。
在ExpressiveConfig中添加以下代碼:
@Value("#{systemProperties['os.name']}")
private String osName;
public void outputResource() {
System.out.println("os.name:" + osName);
}
複製代碼
輸出結果:
os.name:Windows 7
首先,新建一個類DemoService以下所示:
package chapter03.el;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
public class DemoService {
@Value("DemoService類的another屬性")
private String another;
public String getAnother() {
return another;
}
public void setAnother(String another) {
this.another = another;
}
}
複製代碼
而後,在ExpressiveConfig中添加以下代碼:
@Value("#{demoService.another}")
private String fromAnother;
public void outputResource() {
System.out.println("demoService.another:" + fromAnother);
}
複製代碼
表達式中的demoService爲DemoService bean的ID,another是它的屬性。
輸出結果:
demoService.another:DemoService類的another屬性
表達式也能夠修改成調用bean的方法:
@Value("#{demoService.getAnother()}")
private String fromAnother;
複製代碼
輸出結果不變,只是從調用屬性變成了調用方法。
調用完方法,能夠對方法的返回值繼續調用其它方法,好比toUpperCase():
@Value("#{demoService.getAnother()?.toUpperCase()}")
private String fromAnother;
複製代碼
之因此使用"?."運算符,是爲了不當demoService.getAnother()
返回null時,代碼出現NullPointerException。
此時的輸出結果爲:
demoService.another:DEMOSERVICE類的ANOTHER屬性
使用表達式生成1個隨機數:
@Value("#{T(java.lang.Math).random()}")
private double randomNumber;
public void outputResource() {
System.out.println("randomNumber:" + randomNumber);
}
複製代碼
這裏咱們使用T()引用了java.lang.Math類,而後調用了它的靜態方法random()。
輸出結果:
randomNumber:0.6801944394506442
上面的例子中,生成隨機數後,咱們還可使用乘法運算符,以下所示:
@Value("#{T(java.lang.Math).random() * 100.0}")
private double randomNumber;
複製代碼
咱們也能夠在表達式中使用「+」運算符拼接字符串,以下所示:
@Value("#{book.getBookName() + ' write by ' + book.getBookAuthor()}")
private String bookDescr;
public void outputResource() {
System.out.println("bookDescr:" + bookDescr);
}
複製代碼
其中book爲Book bean的ID,輸出結果以下所示:
bookDescr:spring boot write by wangyunfei
也能夠在表達式中使用三元運算符:
@Value("#{systemProperties['os.name'] == 'Windows 7'?'Windows':'Linux'}")
private String osType;
public void outputResource() {
System.out.println("osType:" + osType);
}
複製代碼
由於個人電腦系統是Windows 7,因此輸出結果以下所示:
osType:Windows
SpEL還支持不少的運算符,這裏只是列舉了幾個經常使用的例子,有興趣的同窗能夠本身深刻研究下。
源碼地址:github.com/zwwhnly/spr…,歡迎下載。
Craig Walls 《Spring實戰(第4版)》
汪雲飛《Java EE開發的顛覆者:Spring Boot實戰》
IDEA maven項目src源代碼下的資源文件不自動複製到classes文件夾的解決方法
最後,歡迎關注個人微信公衆號:「申城異鄉人」,全部博客會同步更新。