Spring高階裝配之執行時注入

kbyyd24發表於2016-08-17

原文地址:http://blog.gaoyuexiang.cn/Sp…

執行時注入與硬編碼注入是相對的。硬編碼注入在編譯時就已經確定了,執行時注入則可能需要一些外部的引數來解決。

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主要特性:

  • 使用beanID來引用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.titlenull時,返回"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

相關文章