@Value 與 Spring EL


@Value 用來注入某值,值可以是 Java 基本型態、字串,搭配 PlaceHolder 語法,可以設置系統或 .properties 属性,搭配 Spring EL,可設置運算式結果、其他 Bean 的屬性,搭配特定協定,可以設置文件或者是 URL 資源等。

最單純的就是注入某個值,指定值時一律使用字串指定,若實際上是個整數或者是浮點數,Spring 會自動依注入的對象型態自動剖析,若無法剖析,例如將 @Value("3.14") 標註在 int 的值域上,會發生 NumberFormatException

@Value("guest")
private String name;

@Value("9999")
private int id;

@Value("3.14")
private double pi;

要指定某個屬性,可以使用 @Value("${...}"),例如:

@Value("${spring.profiles.active}")
private String ;

PlaceHolder 可以設定預設值,例如 @Value("${cc.openhome.user:caterpillar}") 的話,在沒有對應的 cc.openhome.user 時,就會使用 "caterpillar" 這個值。

Spring EL 是 Spring 提供的運算式語言(Expression Language),形式為 #{expr},可以搭配 @Value 使用,例如基本的運算、三元運算或者是結合 PlaceHolder 等:

@Value("#{1 + 2.4 * 3}")
private double a;

@Value("#{1 > 2 ? 'Yes' : 'No'}")
private String flag;

@Value("#{'${cc.openhome.workspace}' + '/data'}")
private String dir;

如果想要注入 Spring 管理的某 Bean 的屬性值,例如某個 Bean 實例 getFoo() 的值,可以如下:

@Value("#{beanName.foo}")
private String foo;

也可以進一步呼叫傳回值的方法,例如若 getFoo() 傳回 String 的話,想呼叫其 toUpperCase

@Value("#{beanName.foo.toUpperCase()}")
private String foo;    

getFoo() 可能傳回 null,為了避免 NullPointerException,可以使用 ? 測試,只有在不是 null 的情況下,才會進一步呼叫指定的方法:

@Value("#{beanName.foo?.toUpperCase()}")
private String foo;    

可以使用 #{T(....)} 指定某個類別,並進一步進行操作。指定時必須是類別全名,java.lang 下的類別可以指定類別全名或只指定類別名稱,例如:

@Value("#{T(java.lang.Math).PI}")
private double pi;

@Value("#{T(System).currentTimeMillis()}")

想要指定系統屬性的話,可以使用 #{systemProperties['propName']},例如:

@Value("#{systemProperties['os.name']}")
private String osName;

更多 Spring EL 的說明可以參考〈Spring Expression Language (SpEL)〉。

@Value 也可以注入資源,注入的資源型態是 org.springframework.core.io.Resource 的實作,實際型態依你設定的協定而定,例如::

@Value("classpath:jdbc.properties")
private Resource jdbc;

@Value("https://openhome.cc")
private Resource site;

在上例中,jdbc 實際上注入的會是 ClassPathResource,而 site 會是 UrlResource