SpringBoot加载配置文件的完整步骤是什么

这篇文章给大家介绍SpringBoot加载配置文件的完整步骤是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

目前创新互联已为上千的企业提供了网站建设、域名、网页空间、网站托管、服务器租用、企业网站设计、加格达奇网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。

SpringBoot从哪里开始加载配置文件?

SpringBoot加载配置文件的入口是由ApplicationEnvironmentPreparedEvent事件进入的,SpringBoot会在SpringApplication的构造函数中通过spring.factories文件获取ApplicationListener的实例类:

public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) { ... setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); ...}

spring.factories中有一个ConfigFileApplicationListener类,它会监听ApplicationEnvironmentPreparedEvent然后再加载配置文件 :

# Application Listenersorg.springframework.context.ApplicationListener= org.springframework.boot.context.config.ConfigFileApplicationListener...

有了事件和事件处理的类后,再找出发送事件的地方,就可以搞清楚SpringBoot是怎么加载配置文件的了,SpringBoot在启动之前先初始化好SpringApplicationRunListeners这个类,它会实现SpringApplicationRunListener接口然后对事件进行转发:

class SpringApplicationRunListeners { private final Log log; private final List listeners; SpringApplicationRunListeners(Log log, Collection listeners) { this.log = log; this.listeners = new ArrayList<>(listeners); }  void environmentPrepared(ConfigurableEnvironment environment) { for (SpringApplicationRunListener listener : this.listeners) { listener.environmentPrepared(environment); } } ...}

获取SpringApplicationRunListeners的代码如下:

private SpringApplicationRunListeners getRunListeners(String[] args) { Class[] types = new Class[] { SpringApplication.class, String[].class }; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));}

同样也会去加载spring.factories文件,该文件有一个EventPublishingRunListener类,该类的作用就是SpringBoot的事件转换成ApplicationEvent发送出去。

# Run Listenersorg.springframework.boot.SpringApplicationRunListener=\org.springframework.boot.context.event.EventPublishingRunListener

小结

SpringBoot会将事件转换成ApplicationEvent再分发  SpringBoot是通过监听ApplicationEnvironmentPreparedEvent事件来加载配置文件的  ConfigFileApplicationListener是处理配置文件的主要类

SpringBoot从哪些地方加载配置文件?

上面已经分析到ConfigFileApplicationListener是处理配置文件的主要类,然后进一步的查看SpringBoot是从哪些地址加载配置文件,进入ConfigFileApplicationListener类后会有两个默认的常量:

private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";private static final String DEFAULT_NAMES = "application";

首先在没有任何配置的情况下,会从DEFAULT_SEARCH_LOCATIONS常量列出来的位置中加载文件名为DEFAULT_NAMES(.properties或yml)的文件,默认位置包括:

classpath根目录(classpath:/)  classpath里面的config文件目录(classpath:/config/)  程序运行目录(file:./)  程序运行目录下的config目录(file:./config/)

上面说的是没有额外配置的情况,SpringBoot足够灵活可以指定配置文件搜索路径、配置文件名,在ConfigFileApplicationListener类中有个getSearchLocations方法,它主要负责获取配置搜索目录:

private Set getSearchLocations() {if (this.environment.containsProperty(CONFIG_LOCATION_PROPERTY)) { return getSearchLocations(CONFIG_LOCATION_PROPERTY); } Set locations = getSearchLocations(CONFIG_ADDITIONAL_LOCATION_PROPERTY); locations.addAll( asResolvedSet(ConfigFileApplicationListener.this.searchLocations, DEFAULT_SEARCH_LOCATIONS)); return locations;}

它的操作步骤大致如下:

  1. 检查是否有spring.config.location属性,如果存在则直接使用它的值  从spring.config.additional-location属性中获取搜索路径  将默认搜索路径添加到搜索集合

这里就可以确定SpringBoot配置的搜索路径有两种情况:如果配置了spring.config.location则直接使用,否则使用spring.config.additional-location的属性值 + 默认搜索路径。

SpringBoot是如何支持yaml和properties类型的配置文件?

SpringBoot的配置支持properties和yaml文件,SpringBoot是如何解析这两种文件的呢,继续分析ConfigFileApplicationListener这个类,里面有个子类叫Loader加载配置文件主要的工作就是由这货负责,但是直接读取properties和yaml并转换成PropertySource还是由里面的PropertySourceLoader负责:

Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) { ... this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class, getClass().getClassLoader());}

构造Loader对象的时候就会先加载PropertySourceLoader,加载方式还是从spring.factories中读取:

# PropertySource Loadersorg.springframework.boot.env.PropertySourceLoader=\org.springframework.boot.env.PropertiesPropertySourceLoader,\org.springframework.boot.env.YamlPropertySourceLoader

其中配置了两个PropertySourceLoader的实现类:

PropertiesPropertySourceLoader  YamlPropertySourceLoader

看名字就知道是分别负责properties和yaml的啦。

如果要支持json配置应该如何做?

如果不喜欢properties和yaml这两种格式,想要定义json做为配置文字格式可以直接定义json类型的PropertySourceLoader:

public class JSONPropertySourceLoader implements PropertySourceLoader { @Override public String[] getFileExtensions() { return new String[] {"json"}; }  @Override public List> load(String name, Resource resource) throws IOException { if(resource == null || !resource.exists()){  return Collections.emptyList(); } Map configs = JSON.parseObject(resource.getInputStream(), Map.class); return Collections.singletonList(  new MapPropertySource(name, configs) ); }}

然后在resources目录里面建立个META-INF,再添加个spring.factories里面的内容如下:

org.springframework.boot.env.PropertySourceLoader=\com.csbaic.arch.spring.env.loader.JSONPropertySourceLoader

最后在resources目录里面建个application.json的配置文件 :

{ "spring.application.name": "JSONConfig"}

正常启动SpringBoot获取spring.applicaiton.name的配置的值就是JSONConfig:

2019-11-02 14:50:17.730 INFO 55275 --- [ main] c.c.a.spring.env.SpringEnvApplication : JSONConfig

SpringBoot的配置优先级是怎么样的?

SpringBoot中有个PropertySource接口,专门用来保存属性常见的实现类有:

CommandLinePropertySource  MapPropertySource  SystemEnvironmentPropertySource  ....

另外为了集中管理PropertySource还抽象出一个PropertySources接口,PropertySources就一个实现类叫:MutablePropertySources,它将所有的PropertySource都放置在一个名叫propertySourceList集合中,同时提供一些修改操作方法:

public void addFirst(PropertySource propertySource) {}public void addLast(PropertySource propertySource) {}public void addBefore(String relativePropertySourceName, PropertySource propertySource) {}public void addAfter(String relativePropertySourceName, PropertySource propertySource) {}public int precedenceOf(PropertySource propertySource) { }public PropertySource remove(String name) {}public void replace(String name, PropertySource propertySource) {}

所有的PropertySource都保存在propertySourceList中,越小的索引优先级越高,所以如果想要覆盖属性只要保证优化级够高就行。

placeholder是如何被解析的?

继续分析ConfigFileApplicationListener的Loader子类,在构造时还会创建一个PropertySourcesPlaceholdersResolver,placeholder的解析都由它来完成:

Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) { this.placeholdersResolver = new PropertySourcesPlaceholdersResolver(this.environment);}

分析PropertySourcesPlaceholdersResolver发现,真正完成解析是由PropertyPlaceholderHelper完成,PropertySourcesPlaceholdersResolver 在构造的时候就会创建一个PropertyPlaceholderHelper

public PropertySourcesPlaceholdersResolver(Iterable> sources, PropertyPlaceholderHelper helper) { this.sources = sources; this.helper = (helper != null) ? helper : new PropertyPlaceholderHelper(SystemPropertyUtils.PLACEHOLDER_PREFIX,  SystemPropertyUtils.PLACEHOLDER_SUFFIX, SystemPropertyUtils.VALUE_SEPARATOR, true);}

PropertySourcesPlaceholdersResolver 在创建 PropertyPlaceholderHelper 的时候会传递三个参数:前缀、后缀、默认值分割符,分别由以下三个常量表示:

public static final String PLACEHOLDER_PREFIX = "${";public static final String PLACEHOLDER_SUFFIX = "}";public static final String VALUE_SEPARATOR = ":";

这样 PropertyPlaceholderHelper 在解析placeholder时就能知道以什么格式来解析比如:${spring.application.name}这个placeholder就会被解析成属性值。

总结

SpringBoot的配置非常灵活配置可以来自文件、环境变量、JVM系统属性、配置中心等等,SpringBoot通过PropertySource和PropertySources实现属性优先级、CRUD的统一管理,为开发者提供统一的配置抽象。

关于SpringBoot加载配置文件的完整步骤是什么就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。


网站栏目:SpringBoot加载配置文件的完整步骤是什么
浏览地址:http://scyanting.com/article/pspsgi.html