Spring Boot 加载自定义属性文件(@PropertySource注解)

本文将介绍怎样使用 @PropertySource 注解实现加载自定义的属性文件。

@PropertySource 注解提供了一种方便的声明机制,用于将 PropertySource 添加到 Spring 的环境中,该注解可与 @Configuration 类一起使用。

@PropertySource 注解定义如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(PropertySources.class)
public @interface PropertySource {
    String name() default "";
    String[] value();
    boolean ignoreResourceNotFound() default false;
    String encoding() default "";
    Class<? extends PropertySourceFactory> factory() default PropertySourceFactory.class;
}

其中:

  • value  指示要加载的属性文件(properties)的资源位置

  • name  指明此属性源(PropertySource)的名称

  • ignoreResourceNotFound  指示是否应忽略未能找到属性资源

  • encoding  指定解析资源的字符编码,例如:UTF-8

  • factory  指定自定义 PropertySourceFactory

简单示例

在项目的 resources 目录下面创建一个 app.properties 文件,文件内容如下:

beanName=TestBean

然后,在 @Configuration 配置类中使用 @PropertySource 注解将 app.properties 文件添加到 Spring 的 Environment 环境中。代码如下:

// 实体
public class TestBean {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

// 添加配置类
@Configuration
@PropertySource("classpath:my.properties")
public class AppConfig {

    @Autowired
    private Environment env;

    @Bean
    public TestBean testBean() {
        TestBean testBean = new TestBean();
        testBean.setName(env.getProperty("beanName"));
        return testBean;
    }

}

注意,Environment 对象是 @Autowired 到配置类中,然后在填充 TestBean 对象时使用。鉴于上述配置,执行 testBean.getName() 的将返回“TestBean”。

这里将使用 @SpringBootTest 注解创建一个简单的测试类,代码如下:

@SpringBootTest
class AppConfigTest {

    @Autowired
    private TestBean testBean;

    @Test
    void contextLoads() {
        String name = testBean.getName();
        System.out.println("name=" + name);
    }

}

执行上面测试类,将输出如下信息:

name=TestBean

解析 <bean> 和 @Value 注解中的 ${...} 占位符

为了使用 PropertySource 中的属性去解析 <bean> 定义或 @Value 注释中的 ${...} 占位符,您必须确保在 ApplicationContext 使用的 BeanFactory 中注册了适当的嵌入值解析器。

在 XML 中使用 <context:property-placeholder> 时会自动配置嵌入值解析器。当使用 @Configuration 类时,这可以通过静态 @Bean 方法显式注册 PropertySourcesPlaceholderConfigurer 来实现。但是请注意,通过静态 @Bean 方法显式注册 PropertySourcesPlaceholderConfigurer 通常仅在您需要自定义配置时才需要(例如占位符语法等)。

解析 @PropertySource 资源位置中的 ${...} 占位符

@PropertySource 资源位置中存在的任何 ${...} 占位符都将使用已经注册到环境中的属性集进行解析(包括环境变量等)。例如:

(1)在用户的主目录下面创建一个 my.properties 文件,文件内容如下:

beanName=TestBean(User Home)

(2)在 @PropertySource 注解中,通过 ${user.home} 引用用户主目录路径,使用 file 方式去解析用户主目录下的 my.properties 属性文件。代码如下:

@Configuration
@PropertySource("file:${user.home}/my.properties")
public class AppConfig {

    @Autowired
    private Environment env;

    @Bean
    public TestBean testBean() {
        TestBean testBean = new TestBean();
        testBean.setName(env.getProperty("beanName"));
        return testBean;
    }

}

注意,我们可以将上面的 ${user.home} 中的 user.home 替换成属性文件中的属性配置。如果指定的属性不存在,则可以指定默认值(default_value),默认值由冒号“:”分隔,默认值是可选的,如果未指定默认值且无法解析属性,则会抛出 IllegalArgumentException 异常。如下:

@PropertySource("file:${user.home:default_value}/my.properties")

关于使用 @PropertySource 覆盖属性的说明

如果给定的属性键存在于多个 .properties 属性文件中,则处理的最后一个 @PropertySource 注解将“获胜”并覆盖任何先前具有相同名称的键。

例如:给定两个属性文件 a.properties 和 b.properties,考虑以下两个使用 @PropertySource 注解引用它们的配置类:

// 配置类1
@Configuration
@PropertySource("classpath:/com/myco/a.properties")
public class ConfigA { }

// 配置类2
@Configuration
@PropertySource("classpath:/com/myco/b.properties")
public class ConfigB { }

覆盖顺序取决于这些类在应用程序上下文中注册的顺序。

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(ConfigA.class);
ctx.register(ConfigB.class);
ctx.refresh();

在上面的场景中,b.properties 中的属性将覆盖 a.properties 中存在的任何重复项,因为 ConfigB 是最后注册的。

在某些情况下,在使用 @PropertySource 注释时严格控制属性源排序可能是不切实际的。例如,如果上面的 @Configuration 类是通过组件扫描注册的,则很难预测其顺序。在这种情况下,如果重写很重要,建议用户回退到使用编程式 PropertySource API 实现。

注意:根据 Java 8 约定,此注释是可重复的。但是,所有此类 @PropertySource 注释都需要在同一级别声明:直接在配置类上或作为同一自定义注释上的元注释。不建议混合直接注释和元注释,因为直接注释将有效地覆盖元注释。

我们愈是学习,愈觉得自己的贫乏。 —— 雪莱
0 不喜欢
说说我的看法 -
全部评论(
没有评论
关于
本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,请来信告知:hxstrive@outlook.com
公众号