spring註解注入properties配置文件

早期,若是須要經過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")
      }
)
相關文章
相關標籤/搜索