SpringBoot启动过程之初始化器initializer和监听器listeners
2018-03-27 16:46
711 查看
参考https://my.oschina.net/xiaoqiyiye/blog/1624181 SpringBoot初始化器和监听器
https://www.cnblogs.com/zhangxiaoguang/p/spring-notification.html Spring事件机制http://jinnianshilongnian.iteye.com/blog/1902886 Spring事件机制
Listener类图
initialize(sources); // sources目前是一个MyApplication的class对象
}
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources)); // 把sources设置到SpringApplication的sources属性中,目前只是一个MyApplication类对象
}
this.webEnvironment = deduceWebEnvironment(); // 判断是否是web程序(javax.servlet.Servlet和org.springframework.web.context.ConfigurableWebApplicationContext都必须在类加载器中存在),并设置到webEnvironment属性中
// 从spring.factories文件中找出key为ApplicationContextInitializer的类并实例化后设置到SpringApplication的initializers属性中。这个过程也就是找出所有的应用程序初始化器
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 从spring.factories文件中找出key为ApplicationListener的类并实例化后设置到SpringApplication的listeners属性中。这个过程就是找出所有的应用程序事件监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 找出main类,这里是MyApplication类
this.mainApplicationClass = deduceMainApplicationClass();
}
void initialize(C applicationContext);
}
类名 |
---|
org.springframework.boot.context.config.DelegatingApplicationContextInitializer |
org.springframework.boot.context.ContextIdApplicationContextInitializer |
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer |
org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer |
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer |
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer |
DelegatingApplicationContextInitializer: 委派处理ApplicationContext初始化器,其需要委派处理的初始化器来自Spring环境中的context.initializer.classes属性,该属性可以使用逗号分隔多个初始化器。
ContextIdApplicationContextInitializer:为ApplicationContext设置id。根据以下的配置顺序来设置,spring.application.name、vcap.application.name、spring.config.name,如果环境配置中都没有这些配置,则默认使用“application”来表示,另外还会将profiles也加入到id中去。
ConfigurationWarningsApplicationContextInitializer:输出警告日志信息。
ServerPortInfoApplic
4000
ationContextInitializer:添加一个EmbeddedServletContainerInitializedEvent事件监听,触发设置嵌入的WEB服务启动端口。通过属性local.[namespace].port来设置启动端口,其中namespace为ApplicationContext指定的命名空间,如果命名空间为空,则使用local.server.port属性来表示配置的端口。
SharedMetadataReaderFactoryContextInitializer:和Spring Boot共享CachingMetadataReaderFactory。
AutoConfigurationReportLoggingInitializer:添加一个通用的事件监听Springboot自动配置的报表日志输出。
在上面的初始化器分析中,我们可以看到,通过一些属性的读取可以设置Spring Boot启动过程中的一些参数。初始化器的功能可以在Spring Boot启动前对ApplicationContext进行一些自定义操作。初始化器是在准备上下文阶段调用的。
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { context.setEnvironment(environment); postProcessApplicationContext(context); // 调用初始化器 applyInitializers(context); listeners.contextPrepared(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { context.getBeanFactory().registerSingleton("springBootBanner", printedBanner); } // Load the sources Set<Object> sources = getSources(); Assert.notEmpty(sources, "Sources must not be empty"); load(context, sources.toArray(new Object[sources.size()])); listeners.contextLoaded(context); }
void onApplicationEvent(E event);
}
应用程序事件监听器跟监听事件是绑定的。比如ConfigServerBootstrapApplicationListener只跟ApplicationEnvironmentPreparedEvent事件绑定,LiquibaseServiceLocatorApplicationListener只跟ApplicationStartedEvent事件绑定,LoggingApplicationListener跟所有事件绑定等。key为ApplicationListener的有:org.springframework.boot.context.config.ConfigFileApplicationListener 重要(读取加载springboot配置文件) 转向环境和配置文件的加载
org.springframework.boot.context.config.AnsiOutputApplicationListener(参数spring.output.ansi.enabled)
在springboot环境准备完成以后运行,
如果你的终端支持ANSI,设置彩色输出会让日志更具可读性。
org.springframework.boot.logging.LoggingApplicationListener 根据配置初始化日志系统log
org.springframework.boot.logging.ClasspathLoggingApplicationListener 程序启动时,讲classpath打印到debug日志,启动失败时classpath打印到info日志
org.springframework.boot.autoconfigure.BackgroundPreinitializer
org.springframework.boot.context.config.DelegatingApplicationListener(参数context.listener.classes)
把Listener转发给配置的这些class处理,这样可以支持外围代码不去写spring.factories中的org.springframework.context.ApplicationListener相关配置,保持springboot原来代码的稳定
org.springframework.boot.builder.ParentContextCloserApplicationListener 容器关闭时发出通知,如果父容器关闭,那么自容器也一起关闭
org.springframework.boot.context.FileEncodingApplicationListener(参数spring.mandatory-file-encoding)
在springboot环境准备完成以后运行,获取环境中的系统环境参数,检测当前系统环境的file.encoding和spring.mandatory-file-encoding设置的值是否一样,如果不一样则抛出异常
如果不配置spring.mandatory-file-encoding则不检查
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener (参数liquibase.servicelocator.ServiceLocator)
如果存在,则使用springboot相关的版本进行替代
SpringApplication的执行
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; FailureAnalyzers analyzers = null; configureHeadlessProperty(); //从Spirng.factories中获取key为SpringApplicationListeners的类(目前只有一个实现类EventPublishRunListener)并作为listenners属性的一个listener SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); ... }
private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; //将SpringApplication对象传入,也就传入了SpringApplication的listeners属性 return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)); }
分析run方法之前,先看一下SpringApplication中的一些事件和监听器概念。首先是SpringApplicationRunListeners类和SpringApplicationRunListener类的介绍。SpringApplicationRunListeners内部持有SpringApplicationRunListener集合和1个Log日志类。用于SpringApplicationRunListener监听器的批量执行。SpringApplicationRunListener看名字也知道用于监听SpringApplication的run方法的执行。它定义了5个步骤:starting(run方法执行的时候立马执行;对应事件的类型是ApplicationStartedEvent)
environmentPrepared(ApplicationContext创建之前并且环境信息准备好的时候调用;对应事件的类型是ApplicationEnvironmentPreparedEvent)
contextPrepared(ApplicationContext创建好并且在source加载之前调用一次;没有具体的对应事件)
contextLoaded(ApplicationContext创建并加载之后并在refresh之前调用;对应事件的类型是ApplicationPreparedEvent)
finished(run方法结束之前调用;对应事件的类型是ApplicationReadyEvent或ApplicationFailedEvent)
SpringApplicationRunListener目前只有一个实现类EventPublishingRunListener,它把监听的过程封装成了SpringApplicationEvent事件并让内部属性(intialMulticaster)ApplicationEventMulticaster接口的实现类SimpleApplicationEventMulticaster广播出去,广播出去的事件对象会被SpringApplication中的listeners属性进行处理。所以说SpringApplicationRunListener和ApplicationListener之间
ae93
的关系是通过ApplicationEventMulticaster广播出去的SpringApplicationEvent所联系起来的。
SpringApplicationRunListennersclass SpringApplicationRunListeners {
private final Log log;
private final List<SpringApplicationRunListener> listeners;
SpringApplicationRunListeners(Log log,
Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
this.listeners = new ArrayList<SpringApplicationRunListener>(listeners);
}
public void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
public void environmentPrepared(ConfigurableEnvironment environment) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.environmentPrepared(environment);
}
}
public void contextPrepared(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.contextPrepared(context);
}
}
public void contextLoaded(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.contextLoaded(context);
}
}
public void finished(ConfigurableApplicationContext context, Throwable exception) {
for (SpringApplicationRunListener listener : this.listeners) {
callFinishedListener(listener, context, exception);
}
}
private void callFinishedListener(SpringApplicationRunListener listener,
ConfigurableApplicationContext context, Throwable exception) {
try {
listener.finished(context, exception);
}
catch (Throwable ex) {
if (exception == null) {
ReflectionUtils.rethrowRuntimeException(ex);
}
if (this.log.isDebugEnabled()) {
this.log.error("Error handling failed", ex);
}
else {
String message = ex.getMessage();
message = (message == null ? "no error message" : message);
this.log.warn("Error handling failed (" + message + ")");
}
}
}
}
EventPublishingRunListenerpublic class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
private final SpringApplication application;
private final String[] args;
private final SimpleApplicationEventMulticaster initialMulticaster;
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
@Override
public int getOrder() {
return 0;
}
@Override
@SuppressWarnings("deprecation")
public void starting() {
this.initialMulticaster
.multicastEvent(new ApplicationStartedEvent(this.application, this.args));
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
this.application, this.args, environment));
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
for (ApplicationListener<?> listener : this.application.getListeners()) {
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware) listener).setApplicationContext(context);
}
context.addApplicationListener(listener);
}
this.initialMulticaster.multicastEvent(
new ApplicationPreparedEvent(this.application, this.args, context));
}
@Override
public void finished(ConfigurableApplicationContext context, Throwable exception) {
SpringApplicationEvent event = getFinishedEvent(context, exception);
if (context != null && context.isActive()) {
// Listeners have been registered to the application context so we should
// use it at this point if we can
context.publishEvent(event);
}
else {
// An inactive context may not have a multicaster so we use our multicaster to
// call all of the context's listeners instead
if (context instanceof AbstractApplicationContext) {
for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
.getApplicationListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
if (event instanceof ApplicationFailedEvent) {
this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
}
this.initialMulticaster.multicastEvent(event);
}
}
private SpringApplicationEvent getFinishedEvent(
ConfigurableApplicationContext context, Throwable exception) {
if (exception != null) {
return new ApplicationFailedEvent(this.application, this.args, context,
exception);
}
return new ApplicationReadyEvent(this.application, this.args, context);
}
private static class LoggingErrorHandler implements ErrorHandler {
private static Log logger = LogFactory.getLog(EventPublishingRunListener.class);
@Override
public void handleError(Throwable throwable) {
logger.warn("Error calling ApplicationEventListener", throwable);
}
}
}
相关文章推荐
- Spring Boot启动过程源码分析(二)事件监听器
- Spring Boot学习笔记03--深入了解SpringBoot的启动过程
- Spring Boot启动过程(六)之内嵌Tomcat中StandardHost、StandardContext和StandardWrapper的启动教程详解
- Spring Boot启动过程(四):Spring Boot内嵌Tomcat启动
- spring5/springboot2源码学习 -- spring boot 应用的启动过程
- Spring Boot启动过程(一)
- Spring Boot 2.x 启动全过程源码分析(上)入口类剖析
- SpringBoot 应用程序启动过程探秘
- 深入讲解spring boot中servlet的启动过程与原理
- Spring Boot启动过程(七):Connector初始化
- spring boot启动过程
- Spring Boot启动过程(四)之Spring Boot内嵌Tomcat启动
- SpringBoot——启动方式及过程分析
- SpringBoot内嵌的Tomcat启动过程及其做过的工作
- Spring Boot启动过程(三)
- Spring boot 启动过程解析 logback
- springboot启动过程
- Spring Boot启动过程完全解析(二)
- Spring Boot启动过程(五):Springboot内嵌Tomcat对象的start
- Spring Boot启动过程(六):内嵌Tomcat中StandardHost、StandardContext和StandardWrapper的启动