SpringBoot 2.0 系列004

SpringBoot 2.0 系列004 --启动实战之配置文件

配置文件

配置文件加载流程

很多文档包括官方文档说SB的默认配置文件是application开头的文件,那么是为什么呢?

  • 我们先看下流程图
  •  

由上述流程我们发现,在执行SpringApplication的run方法中的prepareEnvironment子方法时,触发ConfigFileApplicationListener类中的 load方法,完成配置文件的加载

  • ConfigFileApplicationListener分析

public void load() { this.profiles = Collections.asLifoQueue(new LinkedList<Profile>()); this.processedProfiles = new LinkedList<>(); this.activatedProfiles = false; this.loaded = new LinkedHashMap<>(); // 核心初始化方法 负责初始化 profile (spring.profiles.active) // 如果没有则使用默认的AbstractEnvironment类中的(spring.profiles.default)default(可以是application-default名称的,也可以起不加) initializeProfiles(); // 不为空时 循环加载 初始化了 理论上不会为空 while (!this.profiles.isEmpty()) { Profile profile = this.profiles.poll(); // 第二步 此方法加载 文件的前缀 active 以及后缀 和路径 load(profile, this::getPositiveProfileFilter, addToLoaded(MutablePropertySources::addLast, false)); this.processedProfiles.add(profile); } // 默认加载的 load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true)); addLoadedPropertySources();

  • 接 上边标注第二步的位置

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<String> names = (isFolder ? getSearchNames() : NO_SEARCH_NAMES); names.forEach(

1 // 第三步 location是路径 name是文件名 profile则是-defalut部分或者其他-dev之类的 2 (name) -> load(location, name, profile, filterFactory, consumer)); 3 }); 4 }
  • 接上边标注第三步

private void load(String location, String name, Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {

1 // 这里需要注意的是propertySourceLoaders 此处是在new loader的时候初始化的,即我们流程中的addPropertySources一步 2 //底层使用的是META-INF/spring.factories 3 /\*\* org.springframework.boot.env.PropertySourceLoader=\\ 4 org.springframework.boot.env.PropertiesPropertySourceLoader,\\ 5 org.springframework.boot.env.YamlPropertySourceLoader 6 \*/ 7 // 这也就是 文件后缀支持 yml,yaml,properties,xml的原因 8 // 没有名字的情况 9 if (!StringUtils.hasText(name)) { 10 for (PropertySourceLoader loader : this.propertySourceLoaders) { 11 if (canLoadFileExtension(loader, location)) { 12 load(loader, location, profile, 13 filterFactory.getDocumentFilter(profile), consumer); 14 } 15 } 16 } 17 // 带后缀名的情况 18 for (PropertySourceLoader loader : this.propertySourceLoaders) { 19 for (String fileExtension : loader.getFileExtensions()) { 20 String prefix = location + name; 21 fileExtension = "." + fileExtension; 22 // 第四步 通过后缀名方式加载 23 loadForFileExtension(loader, prefix, fileExtension, profile, 24 filterFactory, consumer); 25 } 26 } 27 }
  • 接第四步

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<Document> documents = loadDocuments(loader, name, resource); if (CollectionUtils.isEmpty(documents)) { this.logger.trace("Skipped unloaded config " + description); return; } List<Document> loaded = new ArrayList<>(); for (Document document : documents) { // 文档Filter if (filter.match(document)) { maybeActivateProfiles(document.getActiveProfiles()); addProfiles(document.getIncludeProfiles()); loaded.add(document); } } Collections.reverse(loaded); if (!loaded.isEmpty()) { // consumer对象来自 addToLoaded方法 目的是装载到PropertySources中 loaded.forEach((document) -> consumer.accept(profile, document));

1 // 开启debug后 打印出这句话 表示文件被加载完毕。 2 this.logger.debug("Loaded config file " + description); 3 } 4 } 5 catch (Exception ex) { 6 throw new IllegalStateException("Failed to load property " 7 + "source from location '" + location + "'", ex); 8 } 9 }

配置文件使用

由上述分析可知,默认的配置文件名为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); }

1/\*\* 2 \* 测试自定义加载文件的方式 01 通过启动设置参数 3 \* 设置环境变量 4 \* @param args 5 \*/ 6public static void main02(String\[\] args) throws InterruptedException { 7 System.setProperty("spring.config.name", "ricky01"); 8 System.setProperty("spring.profiles.default", "bgt02"); 9 SpringApplication application = new SpringApplication(SpringBootApplication01.class); 10 application.run(args); 11} 12 13/\*\* 14 \* 测试自定义加载文件的方式 01 通过启动设置参数 15 \* 设置传入参数 16 \* @param args 17 \*/ 18public static void main(String\[\] args) throws InterruptedException { 19 args=new String\[2\]; 20 args\[0\]="--spring.config.name=ricky01"; 21 args\[1\]="--spring.profiles.default=bgt03"; 22 SpringApplication application = new SpringApplication(SpringBootApplication01.class); 23 application.run(args); 24}
  • 结果

公用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

码云:SpringBootLearn

最后

点赞
收藏

评论区

加载中...

相关推荐

springcloud的配置文件的读取顺序

SpringBoot默认支持properties和YAML两种格式的配置文件。前者格式简单,但是只支持键值对。如果需要表达列表,最好使用YAML格式。SpringBoot支持自动加载约定名称的配置文件,例如application.yml。如果是自定义名称的配置文件,就要另找方法了。可惜的是,不像前者有@PropertySource这样方便的加载方式,

SpringBoot 2.0 系列007

SpringBoot2.0系列007WEB容器详解我们知道java常用的两大容器tomcat和jetty,其中SB默认内嵌了tomcat容器。那么SB都支持什么属性呢?参阅ServerProperties.java基本是通用的服务器配置,以及error、Com

Spring boot 配置文件,配置注解详解 (properties 和yml )

从其他框架来看我们都有自己的配置文件,hibernate有hbm,mybatis有properties,同样,Springboot也有全局配置文件。Springboot使用一个全局的配置文件,而且配置文件的名字是固定的。有两种application.propertiesapplication.yml spring

SpringBoot 2.0 系列003

SpringBoot2.0系列003自定义Parent默认我们使用SpringBoot的方式是通过SB的parent项目的方式,此种之前的教程中我们已经演示过了,这里不做赘述。使用自定义parent管理SpringBoot项目

SpringBoot 2.0 系列006

SpringBoot2.0系列006启动实战之注解使用一些误区说明网上很多教程默认使用SpringBootApplcation注解,且只用这个即可扫描启动类包下所有的bean。而官方默认教程使用的是@EnableAutoConfiguration,这个注解

SpringBoot项目优化和Jvm调优

阅读文本大概需要3分钟。项目调优作为一名工程师,项目调优这事,是必须得熟练掌握的事情。在SpringBoot项目中,调优主要通过配置文件和配置JVM的参数的方式进行。一、修改配置文件关于修改配置文件 application.properties。SpringBoot项目详细的配置文件修改文档https: