概述Devtools全局配置@TestPropertySource注解@SpringBootTest的properties属性命令行参数SPRING_APPLICATION_JSONServletConfig、ServletContext随机数配置自定义配置文件(application-dev.properties形式)application.properties@PropertySource 优先级最低参考
相关文章:
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内部默认的配置参数
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,默认为trueinheritProperties: boolean是否从父类继承propertieslocationsvalue: 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@SpringBootTest的properties属性annotationType = TestPropertySource.class; AnnotationDescriptor descriptor = findAnnotationDescriptor(testClass, annotationType); if (descriptor == null) { return new MergedTestPropertySources(); } List attributesList = resolveTestPropertySourceAttributes(testClass); String[] locations = mergeLocations(attributesList); String[] properties = mergeProperties(attributesList); return new MergedTestPropertySources(locations, properties); }
@SpringBootTest的valueproperties属性用于注入一些自定义的注解,语法要求和@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 configurationbuildlibsspringbootconfiguraiton.jar started by 66439 in G:spring boot configurationbuildlibs) 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 shutdownSPRING_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,可以在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]}
其中longint可以限制数据范围,[]是闭区间,()是开区间。
自定义配置文件(application-dev.properties形式)这个应该是我们用的最多的。首先说优先级,文件可以放在以下4个位置,相同文件从上到下覆盖。外部指的是启动应用程序的目录,例如gradle用application插件打包后,运行的脚本目录就是./ :
file:./config,在外部的config目录下file:./,在外部的目录下classpath:/config/,resources/config下classpath:/,resources下
文件的命名为application-[当前激活的环境名].[yml/properties],当前激活的配置可以用spring.profile.active=[当前激活的环境名]定义,多个环境名用逗号分隔,未设置时用default标识。关于如果修改默认的加载路径和文件名,后面会继续讨论。
application.propertiesSpring Boot系统启动时默认会读取的配置文件,支持propertiesyml格式。也就是说,会先加载application.properties,根据spring.profile.active的设置加载相应的application-XX.properties配置,然后按优先级合并配置文件。
不同文件目录下application.properties的优先级和自定义配置文件的顺序是一样的。
类似@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根据资源类型(ClassPathResouceFileSystemResource)生成一个资源名。factory: subClass of PropertySourceFactory 解析资源的工厂类,一般用默认的即可。 参考
Spring Boot 配置的优先级
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)