admin管理员组

文章数量:1566604


回顾前章

说明:本章在之前章节《SringBoot到Spring源码分析之Environment环境装配》的基础上进行继续源码分析。但是本章内容不需要强依赖前面文章,可以单独阅读。

这里先简单总结前面环境对象装配的主要的过程和内容如下:

1、根据SpringApplication对象webApplicationType属性实例化环境对象StandardServletEnvironment。

2、通过环境对象构造器的方式初始化了所有系统环境变量、JDK系统变量、Servlet上下文参数、Servlet配置参数等信息。这些初始化的数据通过Map数据KV结构存根对象(StubPropertySource),按固定的顺序保存到CopyOnWriteArrayList集合中,保存的数据结构类似List<Map<String, Object>>,其中里面的Map的key为环境类型,value为对应环境的信息封装对象。

3、实例化ApplicationConversionService对象,通过构造器方式默认初始化了130多个类型转换器以及格式化组件,这里思考下为什么要在这一步初始化类型转换器和格式化组件。

4、通过单独函数的方式解析main方法参数,如果有的话。

5、尝试解析Active Profiles配置,实际这里不会解析到。

6、将MutablePropertySources封装为ConfigurationPropertySourcesPropertySource。

7、发布环境对象准备完成事件,这一步很关键,也是本章继续分析的重点,因为整个application.properties/yml配置文件就是通过事件回调的方式去解析的。

8、绑定spring.main开头的配置到SpringApplication对象对应的属性中。

9、根据根据第6步解析的spring.main.web-application-type配置值进行判断是否需要重新变换环境对象。如果spring.main.web-application-type有配置的话。

10、解除前面的MutablePropertySources封装

11、整个环境对象装配完成。

下面是前面章节涉及的顶层调用代码:

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
                                       ApplicationArguments applicationArguments) {


   //1、根据SpringApplication对象webApplicationType属性实例化环境对象StandardServletEnvironment。
   //2、通过环境对象构造器的方式初始化了所有系统环境变量、JDK系统变量、Servlet上下文参数、Servlet配置参数等信息。这些初始化的数据通过Map数据KV结构存根对象(StubPropertySource),按固定的顺序保存到CopyOnWriteArrayList集合中,保存的数据结构类似List<Map<String, Object>>,其中里面的Map的key为环境类型,value为对应环境的信息封装对象。
   ConfigurableEnvironment environment = getOrCreateEnvironment();




   //3、实例化ApplicationConversionService对象,通过构造器方式默认初始化了130多个类型转换器已经格式化组件。
   //4、通过单独函数的方式解析main方法参数,如果有的话。
   //5、尝试解析Active Profiles配置,实际这里不会解析到。
   configureEnvironment(environment, applicationArguments.getSourceArgs());


   //6、将MutablePropertySources封装为ConfigurationPropertySourcesPropertySource
   ConfigurationPropertySources.attach(environment);


   //7、发布环境对象准备完成事件,这一步很关键,也是本章继续分析的重点,因为整个application.properties或application.yml配置文件就是通过事件回调的方式去解析的。
   listeners.environmentPrepared(environment);


   //8、绑定spring.main开头的配置到SpringApplication对象对应的属性中。
   bindToSpringApplication(environment);


   if (!this.isCustomEnvironment) {
      //9、根据根据第6步解析的spring.main.web-application-type配置值进行判断是否需要重新变换环境对象。如果spring.main.web-application-type有配置的话。
      environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
            deduceEnvironmentClass());
   }


   //10、解除前面的MutablePropertySources封装
   ConfigurationPropertySources.attach(environment);


   //11、整个环境对象装配完成。
   return environment;
}

再谈事件监听器

我们本章重点分析第7步骤,其它步骤配合前面的《SringBoot到Spring源码分析之Environment环境装配》章节有详细的关键代码截图。第7步骤主要是获取环境准备完成事件回调通知。获取事件监听器原理是读取classpath下所有的META-INF/spring.factories文件,根据事件监听器接口信息匹配逻辑如下:

1、如果实现SmartApplicationListener接口:通过接口全路径名称 + 调用SmartApplicationListener#supportsEventType子类实现方法 + 调用SmartApplicationListener#supportsSourceType子类实现方法结果均为true。

2、如果没有实现SmartApplicationListener接口:直接判断是否实现了传入的接口来匹配,也就是说判断是否是ApplicationListener接口的子类,例如这里的ApplicationListener接口。如果直接实现ApplicationListener接口而没有实现SmartApplicationListener接口的方式,在实现方法中需要自己去判断事件类型来处理相应的事件。例如像下面这样:

@Override
public void onApplicationEvent(ApplicationEvent event) {
   if (event instanceof ApplicationStartingEvent) {
      onApplicationStartingEvent((ApplicationStartingEvent) event);
   }
   else if (event instanceof ApplicationEnvironmentPreparedEvent) {
      onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
   }
   else if (event instanceof ApplicationPreparedEvent) {
      onApplicationPreparedEvent((ApplicationPreparedEvent) event);
   }
   else if (event instanceof ContextClosedEvent
         && ((ContextClosedEvent) event).getApplicationContext().getParent() == null) {
      onContextClosedEvent();
   }
   else if (event instanceof ApplicationFailedEvent) {
      onApplicationFailedEvent();
   }
}


ApplicationEnvironmentPreparedEvent事件监听器

下面是我们通过断点看到找到Springboot web起步依赖默认的环境准备完成事件监听器如下:

 

我们通过断点看到的信息是已经通过Order接口排好序之后的,执行过程也是根据这个顺序来的。下面简单介绍下这默认7个事件监听器:

  • ConfigFileApplicationListener: 解析application.properties/yml以及application-profile.properties/yml配置文件核心事件监听器,也是本章的重点分析对象。

  • AnsiOutputApplicationListener: 根据spring.output.ansi.enabled配置值配置日志打印色彩模式。

  • LoggingApplicationListener: 解析application.properties/yml配置文件logging开头的配置,并将配置信息初始化日志到系统。

  • BackgroundPreinitializer:这个监听器不处理当前的事件。

  • ClasspathLoggingApplicationListener:纯日志打印,启动过程中控制台debug级别的日志关键字“Application started with classpath”相关的信息就是这个监听器打印的。

  • Delegat

本文标签: 配置文件源码SpringBootpropertiesapplication