早期,若是須要經過spring讀取properties文件中的配置信息,都須要在XML文件中配置文件讀取方式。mysql
基於XML的讀取方式:web
1 <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 2 <property name="locations"> 3 <list> 4 <value>classpath:properties/thread-pool.properties</value> 5 </list> 6 </property> 7 </bean>
固然,這種方式能夠統一管理properties配置文件,也能實現代碼的鬆耦合。但爲了方便開發,提升開發效率,spring官方後來提供了基於註解的配置讀取方式。兩種方式各有優點,能夠基於對項目的考慮選擇最合適的方式。接下來就介紹如何經過註解注入properties的配置信息。spring
首先,準備配置文件:sql
1 core.pool.size=2 2 max.pool.size=3 3 keep.alive.time=1 4 task.queue.size=3 5 await.termination.time=5
定義配置類:app
1 package org.cellphone.config; 2 3 import com.google.gson.Gson; 4 import org.springframework.beans.factory.annotation.Value; 5 import org.springframework.context.annotation.Bean; 6 import org.springframework.context.annotation.PropertySource; 7 import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; 8 import org.springframework.stereotype.Component; 9 10 /** 11 * 12 */ 13 @Component 14 @PropertySource("classpath:properties/thread-pool.properties") 15 public class ThreadPoolConfig { 16 /** 17 * 核心線程個數 18 */ 19 @Value("${core.pool.size}") 20 private int corePoolSize; 21 /** 22 * 最大線程個數 23 */ 24 @Value("${max.pool.size}") 25 private int maxPoolSize; 26 /** 27 * 保持心跳時間 28 */ 29 @Value("${keep.alive.time}") 30 private int keeAliveTime; 31 /** 32 * 任務隊列長度 33 */ 34 @Value("${task.queue.size}") 35 private int taskQueueSize; 36 /** 37 * 等待任務結束的時間 38 */ 39 @Value("${await.termination.time}") 40 private int awaitTerminationTime; 41 42 /** 43 * 使用@value註解注入properties中的屬性 44 * 1. 在類名上面使用 @PropertySource("classpath:*") 註解,*表明屬性文件路徑,能夠指向多個配置文件路徑 45 * 若是是多個配置文件,則是 @PropertySource({"classpath:*","classpath:*"....}) 46 * 2. 在字段上直接使用@value註解 47 * 3. 註解內使用${core.pool.size} core.pool.size 表明屬性文件裏面的key 48 * 5. 須要新增 PropertySourcesPlaceholderConfigurer 的 bean 49 * 6. 在 PropertySourcesPlaceholderConfigurer 增長@bean註解,申明返回的是一個bean,不然會注入失敗 50 * 51 */ 52 53 54 55 @Bean 56 public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { 57 return new PropertySourcesPlaceholderConfigurer(); 58 } 59 60 public int getCorePoolSize() { 61 return corePoolSize; 62 } 63 64 public void setCorePoolSize(int corePoolSize) { 65 this.corePoolSize = corePoolSize; 66 } 67 68 public int getMaxPoolSize() { 69 return maxPoolSize; 70 } 71 72 public void setMaxPoolSize(int maxPoolSize) { 73 this.maxPoolSize = maxPoolSize; 74 } 75 76 public int getKeeAliveTime() { 77 return keeAliveTime; 78 } 79 80 public void setKeeAliveTime(int keeAliveTime) { 81 this.keeAliveTime = keeAliveTime; 82 } 83 84 public int getTaskQueueSize() { 85 return taskQueueSize; 86 } 87 88 public void setTaskQueueSize(int taskQueueSize) { 89 this.taskQueueSize = taskQueueSize; 90 } 91 92 public int getAwaitTerminationTime() { 93 return awaitTerminationTime; 94 } 95 96 public void setAwaitTerminationTime(int awaitTerminationTime) { 97 this.awaitTerminationTime = awaitTerminationTime; 98 } 99 100 @Override 101 public String toString() { 102 return new Gson().toJson(this); 103 } 104 }
這裏注入了一個 PropertySourcesPlaceholderConfigurer bean,spring是經過 PropertySourcesPlaceholderConfigurer 的 locations 來查找屬性文件,而後再根據註解將匹配的屬性set進去,下面經過源碼來了解註解能夠進行一些什麼操做。框架
1 public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerSupport implements EnvironmentAware { 2 3 /** 4 * {@value} is the name given to the {@link PropertySource} for the set of 5 * {@linkplain #mergeProperties() merged properties} supplied to this configurer. 6 */ 7 public static final String LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME = "localProperties"; 8 9 /** 10 * {@value} is the name given to the {@link PropertySource} that wraps the 11 * {@linkplain #setEnvironment environment} supplied to this configurer. 12 */ 13 public static final String ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME = "environmentProperties"; 14 15 16 @Nullable 17 private MutablePropertySources propertySources; 18 19 @Nullable 20 private PropertySources appliedPropertySources; 21 22 @Nullable 23 private Environment environment;
下面代碼省略。。。
上面源碼並沒能說明爲何必定要返回這個bean,接下來看父類 PlaceholderConfigurerSupport 的源碼:ide
1 /** 2 * Abstract base class for property resource configurers that resolve placeholders 3 * in bean definition property values. Implementations <em>pull</em> values from a 4 * properties file or other {@linkplain org.springframework.core.env.PropertySource 5 * property source} into bean definitions. 6 * 7 * <p>The default placeholder syntax follows the Ant / Log4J / JSP EL style: 8 * 9 * <pre class="code">${...}</pre> 10 * 11 * Example XML bean definition: 12 * 13 * <pre class="code"> 14 * <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"/> 15 * <property name="driverClassName" value="${driver}"/> 16 * <property name="url" value="jdbc:${dbname}"/> 17 * </bean> 18 * </pre> 19 * 20 * Example properties file: 21 * 22 * <pre class="code">driver=com.mysql.jdbc.Driver 23 * dbname=mysql:mydb</pre> 24 * 25 * Annotated bean definitions may take advantage of property replacement using 26 * the {@link org.springframework.beans.factory.annotation.Value @Value} annotation: 27 * 28 * <pre class="code">@Value("${person.age}")</pre> 29 * 30 * Implementations check simple property values, lists, maps, props, and bean names 31 * in bean references. Furthermore, placeholder values can also cross-reference 32 * other placeholders, like: 33 * 34 * <pre class="code">rootPath=myrootdir 35 * subPath=${rootPath}/subdir</pre> 36 * 37 * In contrast to {@link PropertyOverrideConfigurer}, subclasses of this type allow 38 * filling in of explicit placeholders in bean definitions. 39 * 40 * <p>If a configurer cannot resolve a placeholder, a {@link BeanDefinitionStoreException} 41 * will be thrown. If you want to check against multiple properties files, specify multiple 42 * resources via the {@link #setLocations locations} property. You can also define multiple 43 * configurers, each with its <em>own</em> placeholder syntax. Use {@link 44 * #ignoreUnresolvablePlaceholders} to intentionally suppress throwing an exception if a 45 * placeholder cannot be resolved. 46 * 47 * <p>Default property values can be defined globally for each configurer instance 48 * via the {@link #setProperties properties} property, or on a property-by-property basis 49 * using the default value separator which is {@code ":"} by default and 50 * customizable via {@link #setValueSeparator(String)}. 51 * 52 * <p>Example XML property with default value: 53 * 54 * <pre class="code"> 55 * <property name="url" value="jdbc:${dbname:defaultdb}"/> 56 * </pre> 57 * 58 * @author Chris Beams 59 * @author Juergen Hoeller 60 * @since 3.1 61 * @see PropertyPlaceholderConfigurer 62 * @see org.springframework.context.support.PropertySourcesPlaceholderConfigurer 63 */ 64 public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfigurer 65 implements BeanNameAware, BeanFactoryAware { 66 67 /** Default placeholder prefix: {@value} */ 68 public static final String DEFAULT_PLACEHOLDER_PREFIX = "${"; 69 70 /** Default placeholder suffix: {@value} */ 71 public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}"; 72 73 /** Default value separator: {@value} */ 74 public static final String DEFAULT_VALUE_SEPARATOR = ":"; 75 76 77 /** Defaults to {@value #DEFAULT_PLACEHOLDER_PREFIX} */ 78 protected String placeholderPrefix = DEFAULT_PLACEHOLDER_PREFIX; 79 80 /** Defaults to {@value #DEFAULT_PLACEHOLDER_SUFFIX} */ 81 protected String placeholderSuffix = DEFAULT_PLACEHOLDER_SUFFIX; 82 83 /** Defaults to {@value #DEFAULT_VALUE_SEPARATOR} */ 84 @Nullable 85 protected String valueSeparator = DEFAULT_VALUE_SEPARATOR; 86 87 protected boolean trimValues = false; 88 89 @Nullable 90 protected String nullValue; 91 92 protected boolean ignoreUnresolvablePlaceholders = false; 93 94 @Nullable 95 private String beanName; 96 97 @Nullable 98 private BeanFactory beanFactory;
下面代碼省略。。。
類註釋說明了 PlaceholderConfigurerSupport 類所起的做用,以及替換了XML的哪些操做,其中就描述了注入的bean能夠利用 @Value 註解進行屬性替換:單元測試
* Annotated bean definitions may take advantage of property replacement using * the {@link org.springframework.beans.factory.annotation.Value @Value} annotation: * * <pre class="code">@Value("${person.age}")</pre>
屬性註釋:測試
1 /** Default placeholder prefix: {@value} */ 2 public static final String DEFAULT_PLACEHOLDER_PREFIX = "${"; 3 4 /** Default placeholder suffix: {@value} */ 5 public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}"; 6 7 /** Default value separator: {@value} */ 8 public static final String DEFAULT_VALUE_SEPARATOR = ":"; 9 10 11 /** Defaults to {@value #DEFAULT_PLACEHOLDER_PREFIX} */ 12 protected String placeholderPrefix = DEFAULT_PLACEHOLDER_PREFIX; 13 14 /** Defaults to {@value #DEFAULT_PLACEHOLDER_SUFFIX} */ 15 protected String placeholderSuffix = DEFAULT_PLACEHOLDER_SUFFIX; 16 17 /** Defaults to {@value #DEFAULT_VALUE_SEPARATOR} */ 18 @Nullable 19 protected String valueSeparator = DEFAULT_VALUE_SEPARATOR; 20 21 protected boolean trimValues = false; 22 23 @Nullable 24 protected String nullValue; 25 26 protected boolean ignoreUnresolvablePlaceholders = false;
從上面註解能夠發現,使用的 默認前綴是:'${',然後綴是:'}',默認的分隔符是 ':',可是set方法能夠替換掉默認的分隔符,而 ignoreUnresolvablePlaceholders 默認爲 false,表示會開啓配置文件不存在,拋出異常的錯誤。this
從上面就能看出這個bean所起的做用,就是將 @propertySource 註解的bean注入屬性的做用,若是沒有該bean,則不能解析${}符號。
接下來執行單元測試。
配置類代碼:
1 package org.cellphone.web; 2 3 import org.springframework.context.annotation.ComponentScan; 4 import org.springframework.context.annotation.Configuration; 5 6 /** 7 * 配置類——用來替換xml配置文件 8 */ 9 @Configuration 10 @ComponentScan("org.cellphone.config") 11 public class SpringConfig { 12 }
1 package org.cellphone.web; 2 3 import org.cellphone.config.ThreadPoolConfig; 4 import org.junit.Test; 5 import org.junit.runner.RunWith; 6 import org.slf4j.Logger; 7 import org.slf4j.LoggerFactory; 8 import org.springframework.beans.factory.annotation.Autowired; 9 import org.springframework.test.context.ContextConfiguration; 10 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 11 12 /** 13 * 純註解方式整合Junit單元測試框架測試類 14 */ 15 @RunWith(SpringJUnit4ClassRunner.class) 16 @ContextConfiguration(classes = { SpringConfig.class }) // 須要注意此處,將加載配置文件的註解換成加載配置類的註解 17 public class ThreadPoolConfigTest { 18 19 private final Logger logger = LoggerFactory.getLogger(getClass()); 20 21 @Autowired 22 private ThreadPoolConfig threadPoolConfig; 23 24 @Test 25 public void testThreadPoolConfig() { 26 logger.info(threadPoolConfig.toString()); 27 } 28 }
使用 @PropertySource 註解須要注意如下幾個地方:
1. 使用註解須要將類申明爲一個bean,可使用 @Component 註解;
2. @PropertySource(value = "classpath:properties/config_userbean.properties", ignoreResourceNotFound = true) 表示注入配置文件,而且忽略配置文件不存在的異常;
3. 必須返回一個 PropertySourcesPlaceholderConfigurer 的bean,不然會不能識別@Value("${core.pool.size}") 註解中的 ${core.pool.size}指向的value,而會注入${core.pool.size}的字符串,返回 PropertySourcesPlaceholderConfigurer 的方法,使用 @Bean 註解,表示返回的是個bean。
在spring 4.0之後,spring增長了 @PropertySources 註解,可使用多個 @PropertySource 註解,以下:
@PropertySources( { @PropertySource("classpath:properties/thread-pool.properties"), @PropertySource("classpath:properties/mysql.properties") } )