ConfigurationProperties注解
@ConfigurationProperties注解可以从外部获取配置信息,并将其绑定到JavaBean中。
原理
SpringBoot可以让配置信息外部化,支持的配置有多种,最常见的.properties、.yaml文件,启动时命令行参数--xxx、系统环境变量、Java系统属性(System.getProperties())...
@ConfigurationProperties注解的功能由ConfigurationPropertiesBindingPostProcessor这个后置处理器实现,spring容器中的enviroment.propertySources记录着外部的属性值,properties后置处理器会从中找到匹配的值绑定到JavaBean中。
属性的绑定是会被覆盖的,排序靠后的会覆盖靠前的,即越靠后的优先级越高。(os环境变量可以覆盖application.properties,java系统属性可以覆盖系统环境变量,命令行参数可以覆盖java系统属性...)
这些配置的方式和可以参照spring boot官方文档:
2. Externalized Configuration
Spring Boot lets you externalize your configuration so that you can work with the same application code in different environments. You can use a variety of external configuration sources, include Java properties files, YAML files, environment variables, and command-line arguments.
Property values can be injected directly into your beans by using the
@Valueannotation, accessed through Spring’sEnvironmentabstraction, or be bound to structured objects through@ConfigurationProperties.Spring Boot uses a very particular
PropertySourceorder that is designed to allow sensible overriding of values. Properties are considered in the following order (with values from lower items overriding earlier ones):
- Default properties (specified by setting
SpringApplication.setDefaultProperties).@PropertySourceannotations on your@Configurationclasses. Please note that such property sources are not added to theEnvironmentuntil the application context is being refreshed. This is too late to configure certain properties such aslogging.*andspring.main.*which are read before refresh begins.- Config data (such as
application.propertiesfiles).- A
RandomValuePropertySourcethat has properties only inrandom.*.- OS environment variables.
- Java System properties (
System.getProperties()).- JNDI attributes from
java:comp/env.ServletContextinit parameters.ServletConfiginit parameters.- Properties from
SPRING_APPLICATION_JSON(inline JSON embedded in an environment variable or system property).- Command line arguments.
propertiesattribute on your tests. Available on@SpringBootTestand the test annotations for testing a particular slice of your application.@TestPropertySourceannotations on your tests.- Devtools global settings properties in the
$HOME/.config/spring-bootdirectory when devtools is active.Config data files are considered in the following order:
- Application properties packaged inside your jar (
application.propertiesand YAML variants).- Profile-specific application properties packaged inside your jar (
application-{profile}.propertiesand YAML variants).- Application properties outside of your packaged jar (
application.propertiesand YAML variants).- Profile-specific application properties outside of your packaged jar (
application-{profile}.propertiesand YAML variants).
系统环境变量的方式
这里通过系统环境变量的绑定方式大致记录下,因为java应用的docker镜像通常使用这种方式,例如docker启动指令里加上-e xxx=xxx,就是在指定docker容器的系统环境变量。比较常见的-e JAVA_OPTS=xxx ,因为java应用的镜像通常entrypoint都是sh -c java $JAVA_OPTS xxx.jar。
上文中enviroment.propertySources会读取外部的配置,系统环境变量是通过System.getenv()获取的,通过docker指令给镜像添加了系统环境变量后,就会通过这种方式绑定到java应用的配置类中。
但是
通过docker指令配置系统环境变量的方式,参数的命名需要做对应的调整,例如:
@ConfigurationProperties(prefix="user")
public class Test{
private String name;
}如果是通过.properties文件来配置那么文件中应该是user.name=xxx,如果是通过linux系统环境变量的方式,则环境变量中应该是USER_NAME=xxx.这是因为不同操作系统对环境变量的命名规则都有严格的要求,spring boot的宽松绑定规则要尽可能兼容不同系统的限制.
linux shell变量的命名规则:可以a-zA-Z0-9,可以下划线_,按照惯例,变量名都是大写的。所以,通过环境变量读取java配置时,应该遵循的原则
将
.替换为_删除所有破折号
-变量名转为大写
例:spring.main.log-startup-info -> SPRING_MAIN_LOGSTARTUPINFO
Binding from Environment Variables
Most operating systems impose strict rules around the names that can be used for environment variables. For example, Linux shell variables can contain only letters (
atozorAtoZ), numbers (0to9) or the underscore character (_). By convention, Unix shell variables will also have their names in UPPERCASE.Spring Boot’s relaxed binding rules are, as much as possible, designed to be compatible with these naming restrictions.
To convert a property name in the canonical-form to an environment variable name you can follow these rules:
- Replace dots (
.) with underscores (_).- Remove any dashes (
-).- Convert to uppercase.
For example, the configuration property
spring.main.log-startup-infowould be an environment variable namedSPRING_MAIN_LOGSTARTUPINFO.Environment variables can also be used when binding to object lists. To bind to a
List, the element number should be surrounded with underscores in the variable name.For example, the configuration property
my.service[0].otherwould use an environment variable namedMY_SERVICE_0_OTHER.