執行時注入與硬編碼注入是相對的。硬編碼注入在編譯時就已經確定了,執行時注入則可能需要一些外部的引數來解決。
Spring
提供的兩種在執行時求值的方式:
-
屬性佔位符(Property placeholder)
-
Spring
表示式語言(SpEL)
注入外部的值
使用@PropertySource
註解可以引入.properties
檔案,使用其中的值。
@Configuration
@PropertySource("classpath:jdbc.properties")
public class JDBCConfig {
@Autowired
Environment env;
@Bean
public DataSource dataSource() {
env.getProperties("driver");
...
}
}
深入瞭解Spring
中的Environment
上例的Environment
有如下方法獲取屬性
-
String getProperty(String key);
-
String getProperty(String key, String defaultValue);
-
T getProperty(String key, Class<T> type);
-
T getProperty(String key, Class<T> type, T defaultValue);
這幾個過載方法的作用顧名思義。其中第一、三個方法獲取一個不存在的屬性時,會丟擲IllegalStateException
異常。
可以使用containsProperty(String key)
方法檢視是否存在某個屬性。
其他相關方法:
-
Class<T> getPropertyAsClass(String key, Class<T> targetType)
: 將獲取的屬性轉換為類 -
String[] getActiveProfiles()
: 返回啟用profile
名稱的陣列 -
String[] getDefaultProfiles()
: 返回預設profile
名稱的陣列 -
boolean acceptsProfiles(String... profiles)
: 如果environment
支援給定的profile
,則返回true
解析屬性佔位符
使用佔位符,可將屬性定義到外部的.properties
檔案中,然後使用佔位符插入到bean
中。佔位符使用${...}
包裝屬性名稱。
在Java
配置中使用@Value
註解。
public BlankDisc(@Value("${disc.title}") String title,
@Value("${disc.artist}") String artist) {
this.title = title;
this.artist = artist;
}
使用佔位符必須配置一個PropertySourcesPlaceholderConfigurer bean
,它能夠基於Spring Environment
及其屬性來解析佔位符。
@Bean
public PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
使用Spring
表示式語言進行裝配
SpEL
主要特性:
-
使用
bean
的ID
來引用bean
-
訪問物件的屬性和方法
-
可對值進行算數、關係和邏輯運算
-
正規表示式匹配
-
集合操作
SpEL
還可以用在DI
之外的地方
SpEL
樣例
SpEL
表示式要放在#{ ... }
中,裡面的”…”就是SpEL
表示式。
-
#{1}
常量,結果始終為1
-
#{T(System).currentTimeMillis()}
T()
表示式會將java.lang.System
視為Java
中對應的型別,然後呼叫其方法,獲取當前時間戳。
-
#{dataSource.user}
dataSource
為宣告的其他bean
,這裡可以獲取它的屬性user
-
#{systemProperties[`username`]}
通過systemProperties
物件獲取系統屬性
表示字面量
可表示的字面量有int
,float/double
,String
,boolean
,其中浮點值可以用科學技術法表示:#{6.18E3}
引用bean
、屬性和方法
引用物件 | 表示式 |
---|---|
bean | #{dataSource} |
bean`s field | #{dataSource.user} |
bean`s method | #{dataSource.getPassword()} |
bean`s method`s method | #{dataSource.getPassword().toUpperCase()} |
如果方法返回值為null
,第四種情況會丟擲NullPoniterException
。可以使用:
#{dataSource.getPassword()?.toUpperCase()}
其中的?.
運算子能夠在訪問前確保不為null
,否則返回null
。
在表示式中使用型別
使用T()
表示式來訪問Java
類中的static
方法和常量,在括號內的是類名,返回一個Class
物件,然後呼叫其方法和常量。
SpEL
運算子
運算子型別 | 運算子 | |
---|---|---|
算數運算 | +, -, *, /, %, ^ | |
比較運算 | <, >, ==, <=, >=, lt, gt, eq, le, ge | |
邏輯運算 | and, or, not, | |
條件運算 | ?: (ternary), ?: (Elvis) | |
正規表示式 | matches |
-
Elvis
運算子
利用三元運算子來檢查場景:#{disc.title ?: `Rattle and Hum`}
,當disc.title
為null
時,返回"Rattle and Hum"
。
名稱的來歷據說是因為`?`長得像貓王的頭髮。。。
-
正規表示式
正規表示式利用matches
來支援正則匹配。
計算集合
-
引入一個元素 :
#{jukebox.songs[4].title}
-
隨機選取 :
#{jukebox.songs[T(Math).random() * jukebox.songs.size()].title}
-
從
String
中獲得char
:#{`This is a test`[2]}
-
使用
.?[]
進行過濾,得到符合條件的子集 :#{jukebox.songs.?[artist eq `Aerosmith`]}
-
使用
.^[]
和.$[]
進行過濾,得到第一個和最後一個匹配項 -
使用
.![]
從集合的每個成員選擇特定屬性放入新集合中 :#{jukebox.songs.![title]}
最後四個表示式有點像
lambda
表示式
SpEL
的表示式可以相互組合使用。
更多
Spring
學習筆記:https://github.com/kbyyd24/spring.demo.test/issues