Spring Boot 配置优先级顺序


相关文章:
Spring Boot 配置优先级顺序
【SpringBoot】启动原理源码剖析(加载spring.factories扩展点) 源码中有配置参数加载顺序,正好参考一下

概述

一般在一个项目中,总是会有好多个环境。比如:

开发环境 -> 测试环境 -> 预发布环境【验证环境】 -> 生产环境

每个环境上的配置文件总是不一样的,甚至开发环境中每个开发者的环境可能也会有一点不同,配置读取可是一个让人有点伤脑筋的问题。

Spring Boot提供了一种优先级配置读取的机制来帮助我们从这种困境中走出来。

常规情况下,我们都知道Spring Boot的配置会从application.properties中读取。实际上,从resource目录下的application.properties文件读取是Spring Boot配置链中的一环而已。

Devtools全局配置
@TestPropertySource注解
@SpringBootTest的properties属性
命令行参数
SPRING_APPLICATION_JSON
ServletConfig、ServletContext
JNDI
Java System properties (System.getProperties())
系统环境变量
随机数配置
自定义配置文件
application.properties
@PropertySource
Spring Boot内部默认的配置参数

Devtools全局配置

Developer Tools提供了一些开发帮助工具,在build.gradle添加依赖后启用。

configurations {
    developmentOnly
    runtimeClasspath {
        extendsFrom developmentOnly
    }
    testRuntimeClasspath {
        extendsFrom developmentOnly
    }
}
dependencies {
    developmentOnly("org.springframework.boot:spring-boot-devtools")
}

Spring Boot会读取在计算机用户的home目录下的.spring-boot-devtools.properties文件里的配置参数到该计算级的所有Spring Boot应用中作为顶层配置,如Linux环境下root用户下~/.spring-boot-devtools.properties文件。开发过程中,可以将一些个人参数记录在这个配置文件中,例如ip地址,机器uuid,datasource参数等。在该配置文件中的定义的配置环境并不会影响到应用配置的读取,官方原话是:

Profiles activated in .spring-boot-devtools.properties will not affect the loading of profile-specific configuration files.

但要注意,该配置优先级最高,设置的时候需要做好记录否则会出现"原因不明的bug",不过应该很少人会用到这个功能。分析下源码,就是加了一个配置切面,并把其设置为顶层配置:

public class DevToolsHomePropertiesPostProcessor implements EnvironmentPostProcessor {
    private static final String FILE_NAME = ".spring-boot-devtools.properties";
    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment,
            SpringApplication application) {
        File home = getHomeFolder();//System.getProperty("user.home")获取用户目录
        File propertyFile = (home != null ? new File(home, FILE_NAME) : null);
        if (propertyFile != null && propertyFile.exists() && propertyFile.isFile()) {
            FileSystemResource resource = new FileSystemResource(propertyFile);
            Properties properties;
            try {
                properties = PropertiesLoaderUtils.loadProperties(resource);
                //成功加载后作为顶层配置
                environment.getPropertySources().addFirst(
                        new PropertiesPropertySource("devtools-local", properties));
            }
            catch (IOException ex) {
                throw new IllegalStateException("Unable to load " + FILE_NAME, ex);
            }
        }
    }

@TestPropertySource注解

在测试的时候,可能会使用另一套测试专用的配置,该套配置的优先级高于系统环境变量、java系统参数、程序内部参数,@TestPropertySource注解就是用来指定这一类配置的。该注解一共有5个参数可以设置:

  • inheritLocations: boolean 是否从父类继承locations,默认为true
  • inheritProperties: boolean是否从父类继承properties
  • locations\value: String[]配置文件的路径,路径格式支持类路径(“classpath:/com/spring/test/DemoTest.properties”),或者文件路径(“file:/dir/DemoTest.properties”),路径名支持SpEL但不支持通配符。配置文件格式支持xml和properties,不支持yaml。
  • properties: String[]参数键值对支持3种语法"key=value", “key:value”,“key value”,优先级高于从locations读取的参数。

如果使用注解的时候没有任何参数,那么会从标注了注解的测试类的包中尝试读取配置文件,例如测试类com.spring.test.DemoTest,那么相应的默认配置文件为com.spring.test.DemoTest.properties,如果没有找到默认的配置文件则抛出非法状态异常。
AbstractTestContextBootstrapper在初始化上下文的时候会调用一个读取、合并配置的方法buildMergedContextConfiguration,该方法通过工具类TestPropertySourceUtils读取类的注解信息。TestPropertySourceUtils从类的注解解析配置信息后返回一个可合并的配置源。

作者:看不见的BUG
链接:https://www.jianshu.com/p/3fc6a78eed31
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

static MergedTestPropertySources buildMergedTestPropertySources(Class<?> testClass) {
        Class<TestPropertySource> annotationType = TestPropertySource.class;
        AnnotationDescriptor<TestPropertySource> descriptor = findAnnotationDescriptor(testClass, annotationType);
        if (descriptor == null) {
            return new MergedTestPropertySources();
        }

        List<TestPropertySourceAttributes> attributesList = resolveTestPropertySourceAttributes(testClass);
        String[] locations = mergeLocations(attributesList);
        String[] properties = mergeProperties(attributesList);
        return new MergedTestPropertySources(locations, properties);
    }

@SpringBootTest的properties属性

@SpringBootTest的value\properties属性用于注入一些自定义的注解,语法要求和@TestPropertySource的properties一样,这里就不详细展开了。

命令行参数

用命令行方式启动Spring Boot应用程序的时候,可以注入一些配置参数,参数的格式是–key=name。举个简单的例子,程序直接输出一个参数,然后打成jar包后运行。

@SpringBootApplication
@Slf4j
public class App implements CommandLineRunner {

    @Value("${cl.name:undefined}")
    private String commandLineName;

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        log.info("Command line arguments: {}", Arrays.toString(args));
        log.info("commandLineName: {}", commandLineName);
    }
}

运行:
java -jar .\springbootconfiguraiton.jar --cl.name="Spring Boot Arguments"
从输出的结果中可以看到可以读取到命令行中的配置。


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.2.RELEASE)

2019-05-25 17:41:36.763  INFO 14416 --- [           main] demo.App                                 : Starting App on DESKTOP-HTJRA28 with PID 14416 (G:\spring boot configuration\build\libs\springbootconfiguraiton.jar started by 66439 in G:\spring boot configuration\build\libs)
2019-05-25 17:41:36.769  INFO 14416 --- [           main] demo.App                                 : No active profile set, falling back to default profiles: default
2019-05-25 17:41:36.859  INFO 14416 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@555590: startup date [Sat May 25 17:41:36 CST 2019]; root of context hierarchy
2019-05-25 17:41:39.662  INFO 14416 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2019-05-25 17:41:39.705  INFO 14416 --- [           main] demo.App                                 : Started App in 3.534 seconds (JVM running for 4.473)
2019-05-25 17:41:39.708  INFO 14416 --- [           main] demo.App                                 : Command line arguments: [--cl.name=Spring Boot Arguments]
2019-05-25 17:41:39.709  INFO 14416 --- [           main] demo.App                                 : commandLineName: Spring Boot Arguments
2019-05-25 17:41:39.714  INFO 14416 --- [       Thread-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@555590: startup date [Sat May 25 17:41:36 CST 2019]; root of context hierarchy
2019-05-25 17:41:39.730  INFO 14416 --- [       Thread-2] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown

SPRING_APPLICATION_JSON

可以在环境变量中定义一个key为SPRING_APPLICATION_JSON的参数,值为json字符串,Spring Boot会解析该json字符串作为参数注入到系统中。SPRING_APPLICATION_JSON可以定义在环境变量、系统配置中,命令行也是可以的,例如命令行参数中用到的demo,执行以下的命令也应该能得到相同的参数结果。
java -jar .\springbootconfiguraiton.jar SPRING_APPLICATION_JSON=’{“cl”:{“name”=“Spring Boot Arguments”}}’
结果输出是undefined,不知道原因,这个配置方式用的应该也很少,放弃研究。。。

ServletConfig、ServletContext

优先级是ServletConfig > ServletContext,可以在application.yml中设置:

server:
  servlet:
    context-parameters:
      scp: 'scpV'

随机数配置

随机数配置大多用于测试,支持的类型如下:

my.secret=${random.value}
my.number=${random.int}
my.bignumber=${random.long}
my.uuid=${random.uuid}
my.number.less.than.ten=${random.int(10)}
my.number.in.range=${random.int[1024,65536]}

其中long\int可以限制数据范围,[]是闭区间,()是开区间。

自定义配置文件(application-dev.properties形式)

这个应该是我们用的最多的。首先说优先级,文件可以放在以下4个位置,相同文件从上到下覆盖。外部指的是启动应用程序的目录,例如gradle用application插件打包后,运行的脚本目录就是./ :

  • file:./config,在外部的config目录下
  • file:./,在外部的目录下
  • classpath:/config/,resources/config下
  • classpath:/,resources下

文件的命名为application-[当前激活的环境名].[yml/properties],当前激活的配置可以用spring.profile.active=[当前激活的环境名]定义,多个环境名用逗号分隔,未设置时用default标识。关于如果修改默认的加载路径和文件名,后面会继续讨论。

application.properties

Spring Boot系统启动时默认会读取的配置文件,支持properties\yml格式。也就是说,会先加载application.properties,根据spring.profile.active的设置加载相应的application-XX.properties配置,然后按优先级合并配置文件。
不同文件目录下application.properties的优先级和自定义配置文件的顺序是一样的。

@PropertySource 优先级最低

类似@TestPropertySource注解,在项目中可以方便的注入自定义的配置文件,注解一共有5个参数:

  • value: String[] 配置文件的路径,路径格式支持类路径(“classpath:/com/spring/test/DemoTest.properties”),或者文件路径(“file:/dir/DemoTest.properties”),路径名支持SpEL但不支持通配符。配置文件格式支持xml和properties,不支持yaml。
  • encoding: String 字符集,默认为空,使用系统的字符集。
  • ignoreResourceNotFound: boolean 当找不到资源文件时,是否忽略,默认为false,找不到资源的时候会报错。
  • name: String 每一套PropertySource都有一个唯一的资源限定名,可以通过propertySource.getName()获取,默认为空,Spring根据资源类型(ClassPathResouce\FileSystemResource)生成一个资源名。
  • factory: subClass of PropertySourceFactory 解析资源的工厂类,一般用默认的即可。

参考

Spring Boot 配置的优先级

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值