這篇要來記錄在 Spring MVC 中,
要如何動態地設定 Properties 給 $Value
用的方法。
我們都知道在 spring MVC 中,如果設定了 PropertySourcesPlaceholderConfigurer
,
我們可以把 property file 中的 Key-Value 值讀進來,
之後在 @Component, @Controller, @Service, @Bean 等 Spring 為我們裝配的物件中,
就可以使用 @Value 來取得
property value,例如:
PropertySourcePlaceholderConfigurer 的設定,有兩種方法,使用 xml 或 java config:
- 使用 xml:
- 使用 java config:
mvc-config.xml:
<bean id="propertyConfigurer" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:xxx1.properties</value> <value>classpath:xxx2.properties</value> </list> </property> <property name="ignoreUnresolvablePlaceholders" value="true" /> </bean>
import java.io.IOException; import java.util.Properties; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.core.env.Environment; @Configuration @PropertySource("classpath:xxx1.properties") @PropertySource("classpath:xxx2.properties") public class MyPropertyConfiguration { @Bean public static PropertySourcesPlaceholderConfigurer setPropertySourcesPlaceholderConfigurer() { PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer(); propertySourcesPlaceholderConfigurer.setIgnoreUnresolvablePlaceholders(true); return propertySourcesPlaceholderConfigurer; } }
Java 中就可以使用 @Value:
@Component public class Test ... @Value("${xxxPropertyKey}") String xxxPropertyKey; ... }
但是這樣子因為 property file 的內容本身是寫死的,
如果今天我們想要注入的 @Value 值是專案啟動時動態決定的,
例如從 Database 中讀取而來、從環境變數 (Environment) 中取得、從網路上讀取 (例如 AWS 的 Parameter Store 服務) 等等,
就不能這樣設定了。
我們必須自己實作 PropertySourcesPlaceholderConfigurer 並覆寫掉 (Override) 它的
postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
方法,在裡面實作增添修改 property key-value 值的程式邏輯,
實作的範例如下:
Java:
import java.io.IOException; import java.util.Properties; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.core.env.Environment; @Configuration @PropertySource("classpath:xxx1.properties") @PropertySource("classpath:xxx2.properties") public class MyParameterStorePropertyConfiguration { //如果原本這邊就有做讀 xxx1.properties 和 xxx2.properties 的 PropertySourcesPlaceholderConfigurer 設定, //不能因為多做了 setMyParameterStorePropertySourcesPlaceholderConfigurer_2() 就把 setMyParameterStorePropertySourcesPlaceholderConfigurer_1() 拿掉, //不然 xxx1.properties 和 xxx2.properties 的 property 都會被 //setMyParameterStorePropertySourcesPlaceholderConfigurer_2() 移掉,因為 //setMyParameterStorePropertySourcesPlaceholderConfigurer_2() 中已經用新的 Properties 取代了原本從 xxx1.properties 和 xxx2.properties 讀到的 property @Bean public static PropertySourcesPlaceholderConfigurer setMyParameterStorePropertySourcesPlaceholderConfigurer_1() { PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer(); propertySourcesPlaceholderConfigurer.setIgnoreUnresolvablePlaceholders(true); //如果不想用 @PropertySource,也可以直接用程式設定,像下面這樣 //propertySourcesPlaceholderConfigurer.setLocations(new ClassPathResource("xx1.properties"), new ClassPathResource("xx2.properties")); return propertySourcesPlaceholderConfigurer; } @Bean public static PropertySourcesPlaceholderConfigurer setMyParameterStorePropertySourcesPlaceholderConfigurer_2(Environment environment) { //可視需要看要不要取得環境變數 (Environment) PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer() { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { Properties properties = new Properties(); //動態地設定 property,key-value 值可能從其他地方來,而非寫死的 property file, //例如從 Database 中讀取而來、從環境變數 (Environment) 中取得、從網路上讀取 (例如 AWS 的 Parameter Store 服務) 等等 //do your logic code here to get xxxKey1, xxxValue1, xxxKey2, xxxValue2, ...... properties.put(xxxKey1, xxxValue1); properties.put(xxxKey2, xxxValue2); //...... setProperties(properties); super.postProcessBeanFactory(beanFactory); } }; propertySourcesPlaceholderConfigurer.setIgnoreUnresolvablePlaceholders(true); return propertySourcesPlaceholderConfigurer; } }
參考資料: