SpringBoot 2.0 系列004 --启动实战之配置文件
配置文件
配置文件加载流程
很多文档包括官方文档说SB的默认配置文件是application开头的文件,那么是为什么呢?
由上述流程我们发现,在执行SpringApplication的run方法中的prepareEnvironment子方法时,触发ConfigFileApplicationListener类中的 load方法,完成配置文件的加载
- ConfigFileApplicationListener分析
public void load() {
this.profiles = Collections.asLifoQueue(new LinkedList
- 接 上边标注第二步的位置
private void load(Profile profile, DocumentFilterFactory filterFactory,
DocumentConsumer consumer) {
// getSearch 如果你配置了spring.config.location 路径 则使用此处路径
// 否则是用默认的 ConfigFileApplicationListener.DEFAULT_SEARCH_LOCATIONS
// 即 private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";
getSearchLocations().forEach((location) -> {
boolean isFolder = location.endsWith("/");
// getSearchNames 是你配置文件的名称 ,如果配置了spring.config.name 则使用配置的这个名字
// 否则使用默认的 private static final String DEFAULT_NAMES = "application";
// 这就是默认是application这个名字的原因
Set
// 第三步 location是路径 name是文件名 profile则是-defalut部分或者其他-dev之类的
(name) -> load(location, name, profile, filterFactory, consumer));
});
}
- 接上边标注第三步
private void load(String location, String name, Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
// 这里需要注意的是propertySourceLoaders 此处是在new loader的时候初始化的,即我们流程中的addPropertySources一步
//底层使用的是META-INF/spring.factories
/\*\* org.springframework.boot.env.PropertySourceLoader=\\
org.springframework.boot.env.PropertiesPropertySourceLoader,\\
org.springframework.boot.env.YamlPropertySourceLoader
\*/
// 这也就是 文件后缀支持 yml,yaml,properties,xml的原因
// 没有名字的情况
if (!StringUtils.hasText(name)) {
for (PropertySourceLoader loader : this.propertySourceLoaders) {
if (canLoadFileExtension(loader, location)) {
load(loader, location, profile,
filterFactory.getDocumentFilter(profile), consumer);
}
}
}
// 带后缀名的情况
for (PropertySourceLoader loader : this.propertySourceLoaders) {
for (String fileExtension : loader.getFileExtensions()) {
String prefix = location + name;
fileExtension = "." + fileExtension;
// 第四步 通过后缀名方式加载
loadForFileExtension(loader, prefix, fileExtension, profile,
filterFactory, consumer);
}
}
}
- 接第四步
private void loadForFileExtension(PropertySourceLoader loader, String prefix, String fileExtension, Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) { DocumentFilter defaultFilter = filterFactory.getDocumentFilter(null); DocumentFilter profileFilter = filterFactory.getDocumentFilter(profile); // 前边说的 -default和-dev部分 if (profile != null) { // Try profile-specific file & profile section in profile file (gh-340) // prefix 是路径名+文件名 // fileExtension是.yml这种 // profile 则是第一步initializeProfiles 是this.profiles注入的 String profileSpecificFile = prefix + "-" + profile + fileExtension; // 各处执行装载 扫描不同路径下是否有对应配置文件 load(loader, profileSpecificFile, profile, defaultFilter, consumer); load(loader, profileSpecificFile, profile, profileFilter, consumer); // Try profile specific sections in files we've already processed for (Profile processedProfile : this.processedProfiles) { if (processedProfile != null) { String previouslyLoaded = prefix + "-" + processedProfile + fileExtension; load(loader, previouslyLoaded, profile, profileFilter, consumer); } } } // Also try the profile-specific section (if any) of the normal file //// 各处执行装载 扫描不同路径下是否有对应配置文件 // 第五步 load(loader, prefix + fileExtension, profile, profileFilter, consumer); }
- 接 第五步
第三步和第四步都会执行下面的方法
private void load(PropertySourceLoader loader, String location, Profile profile,
DocumentFilter filter, DocumentConsumer consumer) {
try {
Resource resource = this.resourceLoader.getResource(location);
String description = getDescription(location, resource);
if (profile != null) {
description = description + " for profile " + profile;
}
if (resource == null || !resource.exists()) {
this.logger.trace("Skipped missing config " + description);
return;
}
if (!StringUtils.hasText(
StringUtils.getFilenameExtension(resource.getFilename()))) {
this.logger.trace("Skipped empty config extension " + description);
return;
}
String name = "applicationConfig: [" + location + "]";
// 转换成docment对象
List
// 开启debug后 打印出这句话 表示文件被加载完毕。
this.logger.debug("Loaded config file " + description);
}
}
catch (Exception ex) {
throw new IllegalStateException("Failed to load property "
+ "source from location '" + location + "'", ex);
}
}
配置文件使用
由上述分析可知,默认的配置文件名为application(-{profile}).yml/xml/yaml/properties,且默认支持项目的resources路径
问题1 怎么使用名称不是application的文件?
根据流程分析可知,文件默认完整名称是由spring.config.name和spring.profiles.default两条属性控制。由此可知,在启动前注入此属性即可。
目标 ,修改默认application为ricky01 ,defalut默认bgt01
在resources新建如下几个文件及内容
默认端口是8010 其他是8011,8012,8013,
- 注入 spring.config.name和spring.profiles.default属性
主要有如下3种方式
/** * 测试自定义加载文件的方式 01 通过启动设置参数 * --spring.config.name=ricky01 --spring.profiles.default=bgt01 * @param args */ public static void main01(String[] args) throws InterruptedException { SpringApplication application = new SpringApplication(SpringBootApplication01.class); application.run(args); }
/\*\*
\* 测试自定义加载文件的方式 01 通过启动设置参数
\* 设置环境变量
\* @param args
\*/
public static void main02(String\[\] args) throws InterruptedException {
System.setProperty("spring.config.name", "ricky01");
System.setProperty("spring.profiles.default", "bgt02");
SpringApplication application = new SpringApplication(SpringBootApplication01.class);
application.run(args);
}
/\*\*
\* 测试自定义加载文件的方式 01 通过启动设置参数
\* 设置传入参数
\* @param args
\*/
public static void main(String\[\] args) throws InterruptedException {
args=new String\[2\];
args\[0\]="--spring.config.name=ricky01";
args\[1\]="--spring.profiles.default=bgt03";
SpringApplication application = new SpringApplication(SpringBootApplication01.class);
application.run(args);
}
- 结果
公用ricky01.yml中的contextpath,服务端口却是各自定义的。以下是bgt03时的启动日志
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.0.1.RELEASE)
2018-05-16 13:40:25.165 INFO 24984 --- [ main] com.ricky.SpringBootApplication01 : Starting SpringBootApplication01 on jsb-bgt with PID 24984 (D:\work\ideawork\SpringBootLearn\chapter04\target\classes started by zdwljs in D:\work\ideawork\SpringBootLearn) 2018-05-16 13:40:25.169 INFO 24984 --- [ main] com.ricky.SpringBootApplication01 : No active profile set, falling back to default profiles: bgt03 2018-05-16 13:40:25.263 INFO 24984 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@3e92efc3: startup date [Wed May 16 13:40:25 CST 2018]; root of context hierarchy 2018-05-16 13:40:28.721 INFO 24984 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8013 (http) 2018-05-16 13:40:28.756 INFO 24984 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2018-05-16 13:40:28.757 INFO 24984 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.29 2018-05-16 13:40:28.770 INFO 24984 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [D:\Program Files\Java\jdk1.8.0_161\bin;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;d:\work\Git\cmd;C:\Program Files (x86)\MySQL\MySQL Server 5.5\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\Users\zdwljs\AppData\Local\Microsoft\WindowsApps;D:\Program Files\Java\jdk1.8.0_161\bin;;.] 2018-05-16 13:40:28.924 INFO 24984 --- [ost-startStop-1] o.a.c.c.C.[.[localhost].[/ricky01] : Initializing Spring embedded WebApplicationContext 2018-05-16 13:40:28.924 INFO 24984 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 3672 ms 2018-05-16 13:40:29.149 INFO 24984 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/] 2018-05-16 13:40:29.155 INFO 24984 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*] 2018-05-16 13:40:29.155 INFO 24984 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*] 2018-05-16 13:40:29.155 INFO 24984 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*] 2018-05-16 13:40:29.155 INFO 24984 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*] 2018-05-16 13:40:29.371 INFO 24984 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2018-05-16 13:40:29.783 INFO 24984 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@3e92efc3: startup date [Wed May 16 13:40:25 CST 2018]; root of context hierarchy 2018-05-16 13:40:29.905 INFO 24984 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest) 2018-05-16 13:40:29.907 INFO 24984 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) 2018-05-16 13:40:29.947 INFO 24984 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2018-05-16 13:40:29.947 INFO 24984 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2018-05-16 13:40:30.183 INFO 24984 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup 2018-05-16 13:40:30.245 INFO 24984 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8013 (http) with context path '/ricky01' 2018-05-16 13:40:30.251 INFO 24984 --- [ main] com.ricky.SpringBootApplication01 : Started SpringBootApplication01 in 5.845 seconds (JVM running for 6.639)
问题2 怎么使用外部配置文件加载 方便统一管理
比如我们放在D:\work\ricky\config目录下管理
- 目标 使用d盘config目录下的文件,如下
第一步 在d盘新建上述文件 默认端口是8020 bgt01端口则是8021
第二步 更改加载路径,如下
这里 只罗列一种方式 其他的和上面修改apllication方式一样
public static void main(String[] args) throws InterruptedException { args=new String[3]; args[0]="--spring.config.location=file:d:/work/ricky/config/"; args[1]="--spring.config.name=ricky02"; args[2]="--spring.profiles.default=bgt01"; SpringApplication application = new SpringApplication(SpringBootApplication02.class); application.run(args); }
- 结果
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.0.1.RELEASE)
2018-05-16 14:09:21.111 INFO 19708 --- [ main] com.ricky.SpringBootApplication02 : Starting SpringBootApplication02 on jsb-bgt with PID 19708 (D:\work\ideawork\SpringBootLearn\chapter04\target\classes started by zdwljs in D:\work\ideawork\SpringBootLearn) 2018-05-16 14:09:21.118 INFO 19708 --- [ main] com.ricky.SpringBootApplication02 : No active profile set, falling back to default profiles: bgt01 2018-05-16 14:09:21.221 INFO 19708 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@1ab06251: startup date [Wed May 16 14:09:21 CST 2018]; root of context hierarchy 2018-05-16 14:09:24.122 INFO 19708 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8021 (http) 2018-05-16 14:09:24.187 INFO 19708 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2018-05-16 14:09:24.187 INFO 19708 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.29 2018-05-16 14:09:24.208 INFO 19708 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [D:\Program Files\Java\jdk1.8.0_161\bin;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;d:\work\Git\cmd;C:\Program Files (x86)\MySQL\MySQL Server 5.5\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\Users\zdwljs\AppData\Local\Microsoft\WindowsApps;D:\Program Files\Java\jdk1.8.0_161\bin;;.] 2018-05-16 14:09:24.427 INFO 19708 --- [ost-startStop-1] o.a.c.c.C.[.[localhost].[/ricky02] : Initializing Spring embedded WebApplicationContext 2018-05-16 14:09:24.429 INFO 19708 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 3225 ms 2018-05-16 14:09:24.748 INFO 19708 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/] 2018-05-16 14:09:24.756 INFO 19708 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*] 2018-05-16 14:09:24.757 INFO 19708 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*] 2018-05-16 14:09:24.757 INFO 19708 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*] 2018-05-16 14:09:24.758 INFO 19708 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*] 2018-05-16 14:09:24.980 INFO 19708 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2018-05-16 14:09:25.424 INFO 19708 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@1ab06251: startup date [Wed May 16 14:09:21 CST 2018]; root of context hierarchy 2018-05-16 14:09:25.583 INFO 19708 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest) 2018-05-16 14:09:25.586 INFO 19708 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) 2018-05-16 14:09:25.672 INFO 19708 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2018-05-16 14:09:25.672 INFO 19708 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2018-05-16 14:09:25.989 INFO 19708 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup 2018-05-16 14:09:26.185 INFO 19708 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8021 (http) with context path '/ricky02' 2018-05-16 14:09:26.191 INFO 19708 --- [ main] com.ricky.SpringBootApplication02 : Started SpringBootApplication02 in 13.196 seconds (JVM running for 14.36)
这里实现的只是外部的,如果你还是需要在项目中则可以修改location=classpath:/XXX/
演示项目地址,欢迎fork和star
最后
作者ricky
交流群:244930845