概述
简介
Spring boot应用,这里具体的来说,是指类SpringApplication
,在其run()
方法运行过程中,主要围绕所使用ApplicationContext
对象的生命周期事件,应用了一个事件监听器机制提供了相应的程序扩展入口点,开发人员可以基于此机制,在相应的事件发生时执行特定的逻辑。
SpringApplication
应用的该事件监听器机制主要利用如下两个类/接口 :
SpringApplicationRunListeners
SpringApplicationRunListener
简单来讲,在SpringApplication的run()
方法执行时,应用上下文ApplicationContext
对象创建之前,应用程序会首先找到配置中所定义的所有SpringApplicationRunListener
的实现类(这些实现类可能由Spring boot自身实现和提供,也可以由开发人员来实现和提供),创建他们的实例,然后把它们放在一个集合中,然后封装为一个 SpringApplicationRunListeners
实例。之后Spring boot应用开始创建ApplicationContext
对象,然后在相应的ApplicationContext
的生命周期事件发生时,程序会通过该SpringApplicationRunListeners
实例向各个 SpringApplicationRunListener
实例广播相应的事件,从而SpringApplicationRunListener
实现类中相应的监听器逻辑得到执行。
这里所提到的SpringApplicationContext
的生命周期事件,具体来讲,是如下事件 :
发生顺序 | 事件 | 简介 |
---|---|---|
1 | environmentPrepared | 环境已经准备好,但是ApplicationContext 实例尚未被创建 |
2 | contextPrepared | ApplicationContext 已经被创建并且准备就绪,但是sources尚未被加载 |
3 | contextLoaded | ApplicationContext 实例的sources已经被加载,但是ApplicationContext 实例尚未被刷新(refresh) |
4 | finished | Spring应用程序启动完成时发送该事件,此时ApplicationContext 实例已经成功创建完成,或者遇到异常创建失败。对于该ApplicationContext 是一个WebApplicationContext 的情况,此时内置的Web容器已经在其他线程启动处于服务就绪状态,而SpringApplication 执行主线程已经完成自己的任务。 |
源代码分析
SpringApplication.run()
方法中事件监听有关逻辑
// SpringApplication 类
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
// 从配置中获取SpringApplicationRunListener实现类并实例化,
// 最终把所有这些实例包装到一个SpringApplicationRunListeners实例来使用
SpringApplicationRunListeners listeners = getRunListeners(args);
// 启动各个SpringApplicationRunListener 监听器实例
listeners.starting();
try {
ApplicationArguments applicationArguments =
new DefaultApplicationArguments(args);
// 准备环境
// 结束时会向各个SpringApplicationRunListener发送事件
// environmentPrepared
ConfigurableEnvironment environment =
prepareEnvironment(listeners,applicationArguments);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();// 这里创建应用上下文
analyzers = new FailureAnalyzers(context);
// 准备应用上下文,
// 完成时会向各个SpringApplicationRunListener发送事件
// contextPrepared
prepareContext(context, environment, listeners,
applicationArguments,printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
// 应用上下文准备完成
// 向各个SpringApplicationRunListener发送事件
// finished
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
// 应用上下文准备遇到异常时,
// 向各个SpringApplicationRunListener发送事件finished,
// 携带响应异常信息
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
SpringApplicationRunListener
实例来自哪里?
上面对SpringApplication.run()
的分析中我们提到"从配置中获取SpringApplicationRunListener
实现类"并实例化,这里我们来看这些实现类具体在哪里配置,是怎样被获取的。
从上面提到的SpringApplication.getRunListeners()
方法开始 :
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// 1.创建一个实例SpringApplicationRunListeners,
// 关于类(SpringApplicationRunListeners下面会有介绍)
// 2.使用方法getSpringFactoriesInstances()获取配置中
// 接口SpringApplicationRunListener实现的实例
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class,
types, this, args));
}
接下来我们看方法getSpringFactoriesInstances
具体都做了些什么 :
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<String>(
//使用工具SpringFactoriesLoader.loadFactoryNames获取指定类type的全限定名,
//而针对本文的情况,这里类type其实就是接口SpringApplicationRunListener
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 实例化这些加载到的类
// 针对本文的情况,在缺省配置Spring boot应用中,获取到的类是
// org.springframework.boot.context.event.EventPublishingRunListener,
// 这里创建该类的一个实例
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
类org.springframework.boot.context.event.EventPublishingRunListener
其是存在于配置文件中:
# spring-boot-1.x.x.RELEASE.jar!META-INFspring.factories 配置文件片段
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=
org.springframework.boot.context.event.EventPublishingRunListener
上面分析中还提到了工具类SpringFactoriesLoader
,关于它可以参考这篇文章,感兴趣的话可以看看。
类SpringApplicationRunListeners
介绍
该类主要是将一组SpringApplicationRunListener聚合到一起,然后使用统一的方式传播事件。
其实现逻辑如下,主要就是将事件传播到各个SpringApplicationRunListener实例。
package org.springframework.boot;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.commons.logging.Log;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.ReflectionUtils;
/**
* A collection of SpringApplicationRunListener.
*
* @author Phillip Webb
*/
class 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 + ")");
}
}
}
}
接口SpringApplicationRunListener
介绍
package org.springframework.boot;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.support.SpringFactoriesLoader;
/**
* SpringApplication run 方法的事件监听器
* SpringApplicationRunListeners are loaded via the SpringFactoriesLoader
* and should declare a public constructor that accepts a SpringApplication
* instance and a String[] of arguments. A new
* SpringApplicationRunListener instance will be created for each run.
*
*/
public interface SpringApplicationRunListener {
/**
* Called immediately when the run method has first started. Can be used for very
* early initialization.
*/
void starting();
/**
* Called once the environment has been prepared, but before the
* ApplicationContext has been created.
* 环境对象准备好后,应用上下文创建前触发该事件
* @param environment the environment
*/
void environmentPrepared(ConfigurableEnvironment environment);
/**
* Called once the ApplicationContext has been created and prepared, but
* before sources have been loaded.
* 应用上下文创建和准备好后,尚未加载sources之前触发该事件
* @param context the application context
*/
void contextPrepared(ConfigurableApplicationContext context);
/**
* Called once the application context has been loaded but before it has been
* refreshed.
* 应用上下文加载sources后,执行refresh之前触发该事件
* @param context the application context
*/
void contextLoaded(ConfigurableApplicationContext context);
/**
* Called immediately before the run method finishes.
*
* SpringApplication 的run方法已经完成自己的任务即将结束之前触发该事件。
* SpringApplication 的run方法即将结束并不代表程序即将退出,只表示run方法任务的完成
* (成功完成或者失败完成)和方法的退出。
* 该事件触发时,应用上下文ApplicationContext要么已经创建成功要么已经创建失败,
* 并且如果是Web应用的情况下,此时Web应用应该已经处于伺服状态(此时应该是存在于其他线程中),
* 而整个进程并不会退出,而当前SpringApplication.run()即将退出。
* @param context the application context or null if a failure occurred before the
* context was created
* @param exception any run exception or null if run completed successfully.
*/
void finished(ConfigurableApplicationContext context, Throwable exception);
}
类EventPublishingRunListener
package org.springframework.boot.context.event;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.ErrorHandler;
/**
* 接口SpringApplicationRunListener的实现类,用于发布各种SpringApplicationEvent事件。
* SpringApplicationEvent事件也是ApplicationEvent事件,但主要是跟踪SpringApplication运行。
*
* 内部使用一个 ApplicationEventMulticaster 实例用于在应用上下文真正被刷新前发布各种事件。
* ApplicationEventMulticaster 实例会管理多个ApplicationListener对象并向它们发布事件。
* 一般应用上下文的事件发布并不是自身直接发布给监听器,而是委托给ApplicationEventMulticaster
* 发布这些事件。
*
* @author Phillip Webb
* @author Stephane Nicoll
*/
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
// 所属SpringApplication对象
private final SpringApplication application;
// 运行参数
private final String[] args;
// 真正用于发布事件所使用的 ApplicationEventMulticaster ,
// 其实是一个 SimpleApplicationEventMulticaster
private final SimpleApplicationEventMulticaster initialMulticaster;
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
// 从appliction中获取已经根据配置实例化的各个ApplicationListener,
// 将它们设置到事件多播器,随后的各种事件发布通过该事件多播器向这些
// ApplicationListener发布
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
@Override
public int getOrder() {
return 0;
}
@Override
@SuppressWarnings("deprecation")
public void starting() {
// 发布事件 ApplicationStartedEvent
this.initialMulticaster
.multicastEvent(new ApplicationStartedEvent(this.application, this.args));
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
// 发布事件 ApplicationEnvironmentPreparedEvent
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
this.application, this.args, environment));
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
// 在应用上下文已经加载但是尚未刷新前将SpringApplication对象中所加载的
// ApplicationListener和应用上下文做关联
for (ApplicationListener<?> listener : this.application.getListeners()) {
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware) listener).setApplicationContext(context);
}
context.addApplicationListener(listener);
}
// 发布事件 ApplicationPreparedEvent
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()) {
// 现在应用上下文存在并且活跃,而且
// 所有的事件监听器都已经关联到应用上下文上面了,所以直接利用应用上下文发布事件
context.publishEvent(event);
}
else {
// 一个不活跃的应用上下文不一定有多播器,所以这里我们使用自己的多播器
// initialMulticaster发布事件
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);
}
}
// 根据上下文和异常情况判断当前是哪种应用程序启动过程结束 :
// 1. SpringApplication启动异常结束,一般启动异常结束也表示程序运行将要结束
// 2. SpringApplication启动正常结束
// 注意:启动正常结束不表示程序运行结束,相反,可能表示程序运行刚就绪开始提供服务
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);
}
}
}
从上面EventPublishingRunListener
的代码可以看出 :
1.EventPublishingRunListener
主要任务是被SpringApplication.run()
调用,负责发布相应事件;
2. EventPublishingRunListener
发布的事件的监听器是SpringApplication
从配置中获取的监听器;
3. EventPublishingRunListener
不仅负责发布事件,而且在合适的时机将SpringApplication
所获取的监听器和应用上下文作关联。
最后
以上就是沉静小虾米为你收集整理的SpringApplication方法run的事件监听器机制简介源代码分析类EventPublishingRunListener的全部内容,希望文章能够帮你解决SpringApplication方法run的事件监听器机制简介源代码分析类EventPublishingRunListener所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复