博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
springboot(三)——application.properties和application.yml是何时解析的
阅读量:5904 次
发布时间:2019-06-19

本文共 6992 字,大约阅读时间需要 23 分钟。

前言

用过的springboot的小伙伴都知道springboot不需要再像springmvc引入那么多的配置文件,只需要加入application.properties或者application.yml即可,比如在上一篇文章讲到数据库的配置,只需要在文件引入如下的配置即可:

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/zplxjj?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8spring.datasource.username=rootspring.datasource.password=@ZPLxjj12345spring.datasource.driver-class-name=com.mysql.jdbc.Driver复制代码

下面简单介绍下springboot在启动的时候是在何时读取的properties和yml文件的内容的

实现一个简单的自定义监听器

第一步:定义一个event,继承ApplicationEvent

public class CustomerApplicationEvent extends ApplicationEvent {    public CustomerApplicationEvent(Object source) {        super(source);        System.out.println("CustomerApplicationEvent constructor...");    }}复制代码

第二步:定义一个listener

@Componentpublic class CustomerApplicationListener implements ApplicationListener
{ @Override public void onApplicationEvent(CustomerApplicationEvent customerApplicationEvent) { System.out.println("customerApplicationEvent:"+customerApplicationEvent.getClass().getName()); }}复制代码

第三步:注册监听器

@SpringBootApplicationpublic class Application {    public static void main(String[] args) {        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);        // 注册 CustomerApplicationListener 事件监听器        context.addApplicationListener(new CustomerApplicationListener());        // 发布 CustomerApplicationEvent 事件        context.publishEvent(new CustomerApplicationEvent(new Object()));    }}复制代码

启动项目后,会发现控制台输出了:

CustomerApplicationEvent constructor...customerApplicationEvent:com.stone.zplxjj.event.CustomerApplicationEvent复制代码

springboot自带的事件

  • ApplicationStartingEvent:应用启动事件,在调用 SpringApplication.run() 方法之前,可以从中获取到 SpringApplication 对象,进行一些启动前设置。
  • ApplicationEnvironmentPreparedEvent:Environment准备完成事件,此时可以从中获取到 Environment 对象并对其中的配置项进行查看或者修改
  • ApplicationPreparedEvent:ApplicationContext准备完成事件,接下来 Spring 就能够向容器中加载 Bean 了 。
  • ApplicationReadyEvent:应用准备完成事件,预示着应用可以接收和处理请求了。
  • ApplicationFailedEvent:应用启动失败事件,可以从中捕获到启动失败的异常信息进行相应处理,例如:添加虚拟机对应的钩子进行资源的回收与释放。

读取配置代码入口:ApplicationEnvironmentPreparedEvent和ConfigFileApplicationListener

加载配置文件需要用到ConfigFileApplicationListener,其代码如下:

@Override	public void onApplicationEvent(ApplicationEvent event) {		if (event instanceof ApplicationEnvironmentPreparedEvent) {			onApplicationEnvironmentPreparedEvent(					(ApplicationEnvironmentPreparedEvent) event);		}		if (event instanceof ApplicationPreparedEvent) {			onApplicationPreparedEvent(event);		}	}复制代码

进入方法:onApplicationEnvironmentPreparedEvent

private void onApplicationEnvironmentPreparedEvent(			ApplicationEnvironmentPreparedEvent event) {		List
postProcessors = loadPostProcessors(); postProcessors.add(this); AnnotationAwareOrderComparator.sort(postProcessors); for (EnvironmentPostProcessor postProcessor : postProcessors) { postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication()); } }复制代码

进入postProcessor.postProcessEnvironment:

//类:ConfigFileApplicationListener	@Override	public void postProcessEnvironment(ConfigurableEnvironment environment,			SpringApplication application) {		addPropertySources(environment, application.getResourceLoader());	}复制代码

进入addPropertySources

protected void addPropertySources(ConfigurableEnvironment environment,			ResourceLoader resourceLoader) {        //将随机方法放入到PropertySources中		RandomValuePropertySource.addToEnvironment(environment);        //load加载		new Loader(environment, resourceLoader).load();	}复制代码

进入load方法:

public void load() {			this.profiles = new LinkedList<>();			this.processedProfiles = new LinkedList<>();			this.activatedProfiles = false;			this.loaded = new LinkedHashMap<>();			initializeProfiles();			while (!this.profiles.isEmpty()) {				Profile profile = this.profiles.poll();				if (profile != null && !profile.isDefaultProfile()) {					addProfileToEnvironment(profile.getName());				}				load(profile, this::getPositiveProfileFilter,						addToLoaded(MutablePropertySources::addLast, false));				this.processedProfiles.add(profile);			}			resetEnvironmentProfiles(this.processedProfiles);			load(null, this::getNegativeProfileFilter,					addToLoaded(MutablePropertySources::addFirst, true));			addLoadedPropertySources();		}复制代码

进入字方法load

private void load(Profile profile, DocumentFilterFactory filterFactory,				DocumentConsumer consumer) {			getSearchLocations().forEach((location) -> {				boolean isFolder = location.endsWith("/");				Set
names = isFolder ? getSearchNames() : NO_SEARCH_NAMES; names.forEach( (name) -> load(location, name, profile, filterFactory, consumer)); }); }复制代码
  • getSearchLocations():首先看CONFIG_LOCATION_PROPERTY,是否存在配置,无则走默认配置路径DEFAULT_SEARCH_LOCATIONS
/**	 * The "config location" property name.	 */	public static final String CONFIG_LOCATION_PROPERTY = "spring.config.location";	// Note the order is from least to most specific (last one wins)	private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";复制代码
  • getSearchNames():首先看CONFIG_NAME_PROPERTY(spring.config.name)配置,否则走DEFAULT_NAMES(application)

**spring.config.name说明:**假如你不喜欢“application.properties”这个默认文件名,你可以重新设定:spring.config.name属性直接指定属性文件名称,spring.config.location属性指定明确路径,但是要注意不能写在application.properties文件里,这样会不起作用,可以写在java -jar xxx.jar --spring.config.name=custom.properties,还可以通过环境变量等方式,yml文件也可以这样

真正加载配置文件的方法:

private void load(String location, String name, Profile profile,				DocumentFilterFactory filterFactory, DocumentConsumer consumer) {			if (!StringUtils.hasText(name)) {				for (PropertySourceLoader loader : this.propertySourceLoaders) {					if (canLoadFileExtension(loader, location)) {						load(loader, location, profile,								filterFactory.getDocumentFilter(profile), consumer);						return;					}				}			}			Set
processed = new HashSet<>(); for (PropertySourceLoader loader : this.propertySourceLoaders) { for (String fileExtension : loader.getFileExtensions()) { if (processed.add(fileExtension)) { loadForFileExtension(loader, location + name, "." + fileExtension, profile, filterFactory, consumer); } } } }复制代码

loader.getFileExtensions():获取所有支持的文件后缀,loader初始化如下:

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

通过加载jar:spring-boot-2.1.4.RELEASE.jar:META-INF/spring.factories文件下对应内容:

# PropertySource Loadersorg.springframework.boot.env.PropertySourceLoader=\org.springframework.boot.env.PropertiesPropertySourceLoader,\org.springframework.boot.env.YamlPropertySourceLoader复制代码

从这里我们可以看到,通过PropertiesPropertySourceLoader和YamlPropertySourceLoader 加载配置文件,具体源码没有细看了,有兴趣自行阅读吧

加载完配置文件,调用方法:addLoadedPropertySources()

结语

至此,springboot加载properties和yml的入口就分析到这里了,细节上肯定不能面面俱到,但是入口知道了,后面就好分析了

本人也开通了微信公众号:stonezplxjj和个人博客:,更多文章欢迎关注公众号:

转载于:https://juejin.im/post/5cbea9a1e51d456e31164a07

你可能感兴趣的文章
LeetCode算法题-Maximum Depth of Binary Tree
查看>>
Cox 教学视频5
查看>>
Jenkins持续集成学习-搭建jenkins问题汇总
查看>>
使用ffmpeg实现对h264视频解码 -- (实现了一个易于使用的c++封装库)
查看>>
flink watermark介绍
查看>>
[Flink原理介绍第四篇】:Flink的Checkpoint和Savepoint介绍
查看>>
Android Xutils 框架
查看>>
C#基础知识整理 基础知识(21) 委托(二)
查看>>
Sysbench 0.5版安装配置
查看>>
书摘—你不可不知的心理策略
查看>>
【博客话题】毕业——开始人生的艰苦历程
查看>>
Linux安装telnet
查看>>
sap scriptfom 多语言翻译
查看>>
黄聪:3分钟学会sessionStorage用法
查看>>
Entity Framework 全面教程详解(转)
查看>>
Windows上Python2.7安装Scrapy过程
查看>>
Chapter 3:Code Style in Django
查看>>
挖掘数据金矿 领军协同创新 曙光荣膺“2016大数据创新应用领袖企业”称号
查看>>
Fast通道获得Win10 Mobile Build 14977更新
查看>>
《BackTrack 5 Cookbook中文版——渗透测试实用技巧荟萃》—第3章3.6节识别操作系统...
查看>>