您的位置:首页 > 编程语言 > Java开发

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类图



SpringApplication构造的时候内部会调用一个private方法initialize:public SpringApplication(Object... sources) {
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();
}
ApplicationContextInitializer,应用程序初始化器,做一些初始化的工作:public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
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);
}

ApplicationListener,应用程序事件(ApplicationEvent)监听器: Spring事件机制见 https://blog.csdn.net/Bob_666/article/details/79714760这里的应用程序事件(ApplicationEvent)有应用程序启动事件(ApplicationStartedEvent),失败事件(ApplicationFailedEvent),准备事件(ApplicationPreparedEvent)等。public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
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);
}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Springboot