Spring使用注解注入属性文件

spring自3.1版本后,增加了新的注解@PropertySource,用于注解注入配置文件的属性

以前,我们配置读取配置文件,一般都是在XML文件里面配置,其实,这不是很利于维护,毕竟要去XML里面找配置,还需要把对象注册为bean,让xml显得过于臃肿,如下就是以前读取xml读取properties文件的配置,相信不少同学都知道.

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
       <list>  
        <value>classpath:properties/config_userbean.properties</value>
        <value>classpath:properties/config_mysql.properties</value>
       </list>
    </property>
</bean> 

但是现在我们有注解的形式来配置了,让我们先来看一段源码,是关于注解@PropertySource注解的

image

从上面的注释,可以发现,@propertySource注解是自spring 3.1版本开始有的,是一个配置注解,用于注入properties文件的属性的.下面,开始上测试代码吧.

--------------------------------我是分割线--------------------------------------

先看配置文件里面的内容:

userBean.name=hexiaowu
userBean.sex=男
userBean.isflag=true</pre>

然后看测试注解注入的类:

@Component
@PropertySource(value = "classpath:properties/config_userbean.properties",ignoreResourceNotFound = true)
public class DemoAnnotation {

   //注入peoperties文件里面的属性
   @Value("${userBean.name}")
   private String propertie_name;

   /**
    *        使用@value注解注入properties中的属性
    *    1.在类名上面使用  @PropertySource("classpath:*") 注解,*代表属性文件路径,可以指向多个配置文件路径
    *        如果是多个配置文件,则是 @PropertySource({"classpath:*","classpath:*"....})
    *    2.ignoreResourceNotFound=true 表示如果配置文件不存在,则忽略报错
    *    3.在字段上直接使用@value注解
    *    4.注解内使用${userBean.name}  userBean.name 代表属性文件里面的key
    *    5.需要新增 PropertySourcesPlaceholderConfigurer   的bean
    *    6.在  PropertySourcesPlaceholderConfigurer 增加@bean注解,申明返回的是一个bean,否则会注入不成功
    *
    */

   @Bean
   public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(){
      return new PropertySourcesPlaceholderConfigurer();
   }

   public String getPropertie_name() {
      return propertie_name;
   }

   public void setPropertie_name(String propertie_name) {
      this.propertie_name = propertie_name;
   }

   @Override
   public String toString() {
      return "DemoAnnotation{"  +
            ", propertie_name='" + propertie_name + '\'' +
            '}';

有同学会很纳闷了,为什么要返回一个 PropertySourcesPlaceholderConfigurer 的bean呢?让我们来看看源码吧.

PS:因为前面本人对 PropertySourcesPlaceholderConfigurer 理解有误,导致下面解释的模棱两可,因为spring是通过PropertySourcesPlaceholderConfigurer 内locations来查找属性文件,然后在根据注解将匹配的属性set进去,而下面的注释解释,是表示用注解可以做一些什么操作..

public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerSupport
        implements EnvironmentAware {

    /**
     * {@value} is the name given to the {@link PropertySource} for the set of
     * {@linkplain #mergeProperties() merged properties} supplied to this configurer.
     */
    public static final String LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME = "localProperties";

    /**
     * {@value} is the name given to the {@link PropertySource} that wraps the
     * {@linkplain #setEnvironment environment} supplied to this configurer.
     */
    public static final String ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME = "environmentProperties";

    private MutablePropertySources propertySources;

    private PropertySources appliedPropertySources;

    private Environment environment;

    下面代码省略.....</pre>

上面源码,并没能看出为什么一定要返回这个bean,那么我看就看看他的父类 PlaceholderConfigurerSupport 吧.以下是父类的源码

/**
 * Abstract base class for property resource configurers that resolve placeholders
 * in bean definition property values. Implementations <em>pull</em> values from a
 * properties file or other {@linkplain org.springframework.core.env.PropertySource
 * property source} into bean definitions.
 *
 * <p>The default placeholder syntax follows the Ant / Log4J / JSP EL style:
 *
 *<pre class="code">${...}</pre>
 *
 * Example XML bean definition:
 *
 *<pre class="code">{@code
 *<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"/>
 *    <property name="driverClassName" value="}${driver}{@code "/>
 *    <property name="url" value="jdbc:}${dbname}{@code "/>
 *</bean>
 *}</pre>
 *
 * Example properties file:
 *
 * <pre class="code"> driver=com.mysql.jdbc.Driver
 * dbname=mysql:mydb</pre>
 *
 * 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>
 *
 * Implementations check simple property values, lists, maps, props, and bean names
 * in bean references. Furthermore, placeholder values can also cross-reference
 * other placeholders, like:
 *
 *<pre class="code">rootPath=myrootdir
 *subPath=${rootPath}/subdir</pre>
 *
 * In contrast to {@link PropertyOverrideConfigurer}, subclasses of this type allow
 * filling in of explicit placeholders in bean definitions.
 *
 * <p>If a configurer cannot resolve a placeholder, a {@link BeanDefinitionStoreException}
 * will be thrown. If you want to check against multiple properties files, specify multiple
 * resources via the {@link #setLocations locations} property. You can also define multiple
 * configurers, each with its <em>own</em> placeholder syntax. Use {@link
 * #ignoreUnresolvablePlaceholders} to intentionally suppress throwing an exception if a
 * placeholder cannot be resolved.
 *
 * <p>Default property values can be defined globally for each configurer instance
 * via the {@link #setProperties properties} property, or on a property-by-property basis
 * using the default value separator which is {@code ":"} by default and
 * customizable via {@link #setValueSeparator(String)}.
 *
 * <p>Example XML property with default value:
 *
 *<pre class="code">{@code
 *  <property name="url" value="jdbc:}${dbname:defaultdb}{@code "/>
 *}</pre>
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @since 3.1
 * @see PropertyPlaceholderConfigurer
 * @see org.springframework.context.support.PropertySourcesPlaceholderConfigurer
 */
public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfigurer
      implements BeanNameAware, BeanFactoryAware {

   /** Default placeholder prefix: {@value} */
   public static final String DEFAULT_PLACEHOLDER_PREFIX = "${";

   /** Default placeholder suffix: {@value} */
   public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";

   /** Default value separator: {@value} */
   public static final String DEFAULT_VALUE_SEPARATOR = ":";

   /** Defaults to {@value #DEFAULT_PLACEHOLDER_PREFIX} */
   protected String placeholderPrefix = DEFAULT_PLACEHOLDER_PREFIX;

   /** Defaults to {@value #DEFAULT_PLACEHOLDER_SUFFIX} */
   protected String placeholderSuffix = DEFAULT_PLACEHOLDER_SUFFIX;

   /** Defaults to {@value #DEFAULT_VALUE_SEPARATOR} */
   protected String valueSeparator = DEFAULT_VALUE_SEPARATOR;

   protected boolean ignoreUnresolvablePlaceholders = false;

   protected String nullValue;

   private BeanFactory beanFactory;

   private String beanName;

类注释表示的是,该类所起的作用,替代了xml文件的哪些操作,我们只需要看下面定义的一个常量注解就能大概知道,为什么需要返回这么一个bean了.

类注释上有这么一句话:表示可以用带注释的bean,可以利用属性符号进行替换

* 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}")

属性注释:

/** Default placeholder prefix: {@value} */
public static final String DEFAULT_PLACEHOLDER_PREFIX = "${";

/** Default placeholder suffix: {@value} */
public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";

/** Default value separator: {@value} */
public static final String DEFAULT_VALUE_SEPARATOR = ":";

/** Defaults to {@value #DEFAULT_PLACEHOLDER_PREFIX} */
protected String placeholderPrefix = DEFAULT_PLACEHOLDER_PREFIX;

/** Defaults to {@value #DEFAULT_PLACEHOLDER_SUFFIX} */
protected String placeholderSuffix = DEFAULT_PLACEHOLDER_SUFFIX;

/** Defaults to {@value #DEFAULT_VALUE_SEPARATOR} */
protected String valueSeparator = DEFAULT_VALUE_SEPARATOR;

protected boolean ignoreUnresolvablePlaceholders = false;

从上面注解可以发现,使用的 默认前缀是: '${', 而后缀是: '}' ,默认的分隔符是 ':', 但是set方法可以替换掉默认的分隔符,而 ignoreUnresolvablePlaceholders 默认为 false,表示会开启配置文件不存在,抛出异常的错误.

从上面就能看出这个bean所起的作用,就是将@propertySource注解的bean注入属性的作用,如果没有该bean,则不能解析${}符号.

下面是测试执行方法:

@Configuration
//扫描带有 @controller @service @Component 等spring注解的类注册为bean
@ComponentScan({"com.spring.annotation.annotationsAttribute"})
public class AnnotationsConfig {
   public static void main(String[] args){
      AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AnnotationsConfig.class);

      DemoAnnotation demoAnnotation = context.getBean(DemoAnnotation.class);

      System.out.println(demoAnnotation.toString());

      context.close();
   }
}

打印结果为:

image

这就表示,我们的注入成功了

使用 @PropertySource注解需要注意以下几个地方

  1. 使用注解需要将类申明被扫描为一个bean,可以使用@Component 注解

  1. @PropertySource(value = "classpath:properties/config_userbean.properties",ignoreResourceNotFound = true) 表示注入配置文件,并且忽略配置文件不存在的异常

  1. 必须返回一个 PropertySourcesPlaceholderConfigurer 的bean,否则,会不能识别@Value("{userBean.name}") 注解中的{userBean.name}指向的value,而会注入${userBean.name}的字符串,返回 PropertySourcesPlaceholderConfigurer 的方法,使用@Bean注解,表示返回的是个bean

在spring 4.0以后,spring增加了@PropertySources 注解,下面是源码

/**
 * Container annotation that aggregates several {@link PropertySource} annotations.
 *
 * <p>Can be used natively, declaring several nested {@link PropertySource} annotations.
 * Can also be used in conjunction with Java 8's support for <em>repeatable annotations</em>,
 * where {@link PropertySource} can simply be declared several times on the same
 * {@linkplain ElementType#TYPE type}, implicitly generating this container annotation.
 *
 * @author Phillip Webb
 * @since 4.0
 * @see PropertySource
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PropertySources {

   PropertySource[] value();

}

从源码的注释,可以看到自4.0以后,@PropertySources注解,可以使用多个@PropertySource注解,代码如下:

@PropertySources(
      {
            @PropertySource("classpath:properties/config_userbean.properties"),
            @PropertySource("classpath:properties/config_mysql.properties")
      }
)

有时候使用@PropertySource 注解会报 找不到这个注解的错误,但是spring确实是3.1以上版本,而且并不影响项目的使用,这样的话,可以使用@propertySources 注解嵌套@propertySource注解,这样就不会报错了

转载自:https://my.oschina.net/u/2278977/blog/794585

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容