Web项目开发中,经常需要自定义一些属性,如数据库连接,第三方服务接口地址,第三方服务的appKey、appSecret等,以及针对不同环境,这些属性的值还需要有相应的调整,如开发环境、测试环境、生产环境所用数据库不同,则针对不同环境的同一属性需要配置不同的值。

传统自定义属性配置及访问(参考Github示例测试类

在传统的Spring Web应用中,自定义属性一般是通过在类路径中(如resources目录)添加一个类似my.properties配置文件(文件名自定义),然后在xml配置中通过

1
<util:properties id="myProps" location="classpath:my.properties"/>

引入属性文件。再定义一个Bean来读取这些属性,Bean配置:

1
2
3
4
5
6
7
8
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="cn.jboost.springboot.properties.MyPropertiesUtil.init"/>
<property name="arguments">
<list>
<ref bean="myProps"/>
</list>
</property>
</bean>

Bean定义:

1
2
3
4
5
6
7
8
9
10
11
12
public class MyPropertiesUtil {

private static Properties properties;

public static void init(Properties props) {
properties = props;
}

public static String getValue(String key) {
return properties.getProperty(key);
}
}

在其它需要访问的地方通过 MyPropertiesUtil.getValue() 方法来访问具体某个属性的值。

Spring Boot自定义属性配置及优先级

在Spring Boot中,可以在多个地方配置属性,包括.properties文件,.yaml文件,环境变量, 系统属性,命令行参数等, 这些属性都会被Spring Boot加载到Environment中,可通过@Value注解,Environment实例,或 @ConfigurationProperties注解的类来访问。

属性加载优先级顺序:

  1. 如果有使用devtools,devtools 全局设置的属性(用户目录 ~/.spring-bootdevtools.properties)
  2. 测试类的注解@TestPropertySource
  3. 测试类注解 @SpringBootTest#properties 配置的属性
  4. 命令行参数
  5. SPRING_APPLICATION_JSON里的属性(环境变量或系统属性)
  6. ServletConfig初始化参数
  7. ServletContext初始化参数
  8. JNDI参数 java:comp/env
  9. Java系统属性 System.getProperties()
  10. 操作系统环境变量
  11. RandomValuePropertySource 配置的属性 random.*
  12. jar包外部的applictaion-{profile}.properties,applictaion-{profile}.yml配置文件
  13. jar包内部的applictaion-{profile}.properties,applictaion-{profile}.yml配置文件
  14. jar包外部的applictaion.properties,applictaion.yml配置文件
  15. jar包内部的applictaion.properties,applictaion.yml配置文件
  16. @Configuration类上的 @PropertySource注解指定的配置文件
  17. 默认属性: SpringApplication.setDefaultProperties

上述属性配置,除了粗体标注的外,其它一般应用较少。序号低的配置优先级高于序号高的配置,即如果存在相同属性配置 ,则序号低的配置会覆盖序号高的配置。applictaion-{profile}.properties 一般用于具体某个环境特有的属性配置,如application-dev.properties用于开发环境,可通过 spring.profiles.active=dev指定加载dev环境配置

常用属性配置方式

  1. 命令行参数
    启动Spring Boot应用时,可以指定命令行参数,如:
    1
    java -jar springboot-properties.jar --my.name=jboost@command_line

该参数值将会覆盖应用在其它地方配置的同名属性值。命令行参数放在xx.jar 的后面。

可以通过SpringApplication.setAddCommandLineProperties(false) 禁用命令行参数配置

  1. Java系统属性
    同样在启动Spring Boot应用时,可以指定Java系统属性,一般见于自定义jvm参数,如:
    1
    java -Dmy.name=jboost@system_properties -jar springboot-properties.jar

Java系统属性放在java命令之后。

  1. 操作系统环境变量(实际应用其实较少)
    配置过JAVA_HOME的应该理解何为环境变量。某些操作系统可能不支持.分隔的属性名,可以改为以下划线连接。Spring Boot将myName, my.name, MY_NAME视为等效。

  2. 应用属性配置文件(.properties文件或 .yml文件)
    .properties文件属性配置格式:

1
2
3
my.name=jboost
my.list[0]=aaa //配置列表
my.list[1]=bbb

.yml文件属性配置格式:

1
2
3
4
5
my:
name: devlink
list: //配置列表
- aaa
- bbb

yml中,属性名与值之间冒号后面必须有空格。

应用属性配置文件位置:

  1. jar包所在当前目录下的子目录/config(外置属性文件)
  2. jar包所在当前目录(外置属性文件)
  3. classpath根目录下的子目录/config(内置属性文件)
  4. classpath根目录(内置属性文件)

序号低的优先级高于序号高的优先级,即jar包外的配置优先级高于jar包内的配置。同一目录下,.properties文件的优先级高于.yml文件。application-{profile}.properties的优先级高于application.properties。

Spring Boot自定义属性访问方式(参考Github示例测试类

  1. 类中属性上添加 @Value(“${xx}”) 注解方式。如:
    1
    2
    @Value("${my.name}")
    private String name;

可以指定默认值,如 @Value(“${my.name:jboost}”), 当my.name未配置时,默认使用值”jboost”

  1. 通过@ConfigurationProperties注解的类来访问。如定义:
    1
    2
    3
    4
    5
    6
    7
    8
    @Component
    @ConfigurationProperties(prefix = "my")
    public class MyConfigProperties {
    private String name;
    private String website;

    //省略了getter、setter函数
    }

然后在需要访问的Bean中,通过@Autowired 注入MyConfigProperties实例,通过getName()方法即可访问my.name属性值。

1
2
3
4
5
6
7
8
9
@Autowired
private MyConfigProperties myConfigProperties;

@Test
public void testConfigurationProperties(){
System.out.println("test @ConfigurationProperties ==========");
System.out.println(myConfigProperties.getName());
System.out.println(myConfigProperties.getWebsite());
}

  1. 通过Environment 实例访问。如:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Autowired
    private Environment env;

    @Test
    public void testEnvironment(){
    System.out.println("test Environment ==========");
    System.out.println(env.getProperty("my.name"));
    System.out.println(env.getProperty("my.website", "default value"));
    }

另外也可以通过 spring-boot-starter-actuator 的接口来查看项目加载的属性配置,在pom.xml中加入 spring-boot-starter-actuator 依赖,因为 spring-boot-starter-actuator 在2.x版本中,出于安全性考虑,将actuator 控件中的端口,只默认开放/health 和/info 两个端口,其他端口默认关闭,因此需要添加配置management.endpoints.web.exposure.include= *,
management.endpoints.web.exposure.exclude=beans,trace,
management.endpoint.health.show-details=ALWAYS,启动项目后,访问 http://localhost:8080/actuator/env ,返回的 propertySources 即为加载的所有属性源,优先级从上往下依次降低,与上文所述优先级相符

本文示例项目源码地址:https://github.com/ronwxy/springboot-demos/tree/master/springboot-properties





我的个人博客地址:http://blog.jboost.cn
我的头条空间: https://www.toutiao.com/c/user/5833678517/#mid=1636101215791112
我的github地址:https://github.com/ronwxy
我的微信公众号:jboost-ksxy

———————————————————————————————————————————————————————————————

微信公众号
欢迎关注我的微信公众号,及时获取最新分享