理解SpringApplicationRunListeners
我们知道Spring Boot应用的启动是依靠SpringApplication.run()来完成的,核心代码如下:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
记得刚学习《Spring Boot编程思想》的时候,小马哥说Spring Boot应用和Spring 应用的区别在于Spring Boot应用是独立的Spring 应用,因为它不需要监听Tomcat/Jetty等Servlet容器来实现普通Spring Web MVC程序的双上下文启动,因为Spring Boot应用只需要run方法即可启动上下文。
对于双上下文的理解,其实读者只需关注Spring和Servlet容器的关系即可理解
- Servlet容器启动,
ContextLoaderListener监听到了,就会启动一个上下文DispatcherServlet(Spring Web MVC应用)作为一个Servlet,随Servlet容器启动后会初始化(如有误请指正),初始化时会创建一个上下文这就是双上下文的产生,能产生两个上下文主要还是因为普通的Spring MVC应用不是独立的Spring应用,它需要强烈关注Servlet容器,随着Servlet容器的启动来启动Spring上下文。
本篇文章会探讨SpringApplication.run()中的SpringApplicationRunListeners对象,通过对其如下的两个方法的剖析加深对SpringApplicationRunListeners的理解,从而对Spring Boot启动流程有一个更深的理解。(对于其在run方法中相关的详细代码不会作过多分析。大佬请绕道!!!)
SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting()
SpringApplicationRunListeners#getRunListeners
创建SpringApplicationRunListeners
private SpringApplicationRunListeners getRunListeners(String[] args) {
// 定义SpringApplicationRunListeners实现类构造器的入参类型和个数
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// this :SpringApplication对象
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
该方法创建了一个SpringApplicationRunListeners对象,下面是SpringApplicationRunListeners类的主要属性和构造方法,其实SpringApplicationRunListeners对象内部包装了SpringApplicationRunListener类型的List集合对象。
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<>(listeners);
}
回到getRunListeners方法
// this : SpringApplication对象
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
SpringApplicationRunListeners创建时,通过getSpringFactoriesInstances()获取了List<SpringApplicationRunListener>对象,我们来看下该方法的逻辑
getSpringFactoriesInstances
// type:SpringApplicationRunListener.class
// parameterTypes: Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// args: SpringApplication对象
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
// 获取ClassLoader,详细代码很简单
ClassLoader classLoader = getClassLoader();
// 获取SpringApplicationRunListener类名的Set对象(去重)
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 创建List<SpringApplicationRunListener>对象
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
SpringFactoriesLoader.loadFactoryNames
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
核心代码就不继续追着看了,我们凭直觉应该能知道又是通过SpringFactoriesLoader工具类去spring.factories文件中寻找SpringApplicationRunListener的实现类类名,然后返回实现类的类名Set
createSpringFactoriesInstances
// type : SpringApplicationRunListener.class
// parameterTypes: Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// names: 类名Set ,先破案,其实只有`EventPublishingRunListener`对象
// args: SpringApplication对象
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
ClassLoader classLoader, Object[] args, Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
// 根据类名Set对象加载SpringApplicationRunListener类
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
// 判断类型
Assert.isAssignable(type, instanceClass);
// 获取EventPublishingRunListener的构造器
// 其实就两个参数 SpringApplication ;String[] args
Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
// 根据构造器创建EventPublishingRunListener对象 ,只传入了SpringApplication对象
// 所以构造器的第二个参数args就是空的String数组
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
该方法根据
SpringFactoriesLoader.loadFactoryNames方法返回的List<String>(类名列表)对象,通过反射逐个创建SpringApplicationRunListener对象,所以SpringApplicationRunListener的实现类必须要有构造方法。
// EventPublishingRunListener的构造器
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
// 下面的构造放到EventPublishimngRunListener部分理解
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
截至目前,
EventPublishingRunListener是Spring Boot官方唯一的SpringApplicationRunListener实现,所以正常情况下我们获取到的List<SpringApplicationRunListener>列表只有EventPublishingRunListener一个元素。当然,我们也可以自己实现
SpringApplicationRunListener,并且声明在Spring Boot应用的META-INF/spring.factories文件中即可。
接下来看看SpringApplicationRunListener和它的实现EventPublishingRunListener。
SpringApplicationRunListener
public interface SpringApplicationRunListener {
/**
* 运行时机: Spring应用刚启动
*/
void starting();
/**
* 运行时机:ConfigurableEnvironment准备妥当,允许将其调整
*/
void environmentPrepared(ConfigurableEnvironment environment);
/**
* 运行时机:ConfigurableApplicationContext准备妥当,允许将其调整
*/
void contextPrepared(ConfigurableApplicationContext context);
/**
* 运行时机:ConfigurableApplicationContext已经装载,但仍未启动
*/
void contextLoaded(ConfigurableApplicationContext context);
/**
* 运行时机:ConfigurableApplicationContext已启动,此时Spring Bean已经初始化完成
*/
void started(ConfigurableApplicationContext context);
/**
* 运行时机:Spring应用正在运行
*/
void running(ConfigurableApplicationContext context);
/**
* 运行时机: Spring应用运行失败
*/
void failed(ConfigurableApplicationContext context, Throwable exception);
}
EventPublishingRunListener
public 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;
// SimpleApplicationEventMulticaster:ApplicationEventMulticaster的实现类;
// 用来发布事件
this.initialMulticaster = new SimpleApplicationEventMulticaster();
// 遍历SpringApplication中的ApplicationListener列表对象将其添加给SimpleApplicationEventMulticaster
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
...
}
前面在创建SpringApplicationRunListeners过程,我们已经简单过了一下
EventPublishingRunListener的构造器,也就是前两行的内容
这是
SpringApplication对象中的ApplicationListener列表。
我们认真理解了SpringApplicationRunListeners的创建过程,其实就是创建List<SpringApplicationRunListener>对象,再深了说就是创建EventPublishingRunListener对象;而EventPublishingRunListener对象的创建引入了SimpleApplicationEventMulticaster对象。我们再来看SpringApplication.run()方法:listeners.starting();方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
...
}
SpringApplicationRunListeners#starting
SpringApplicationRunListeners#starting
public void starting() {
// 遍历SpringApplicationRunListener列表 调用starting方法
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
EventPublishingRunListener#starting
@Override
public void starting() {
// 发布ApplicationStartingEvent事件 args为空
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
SimpleApplicationEventMulticaster部分代码
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
...
@Override
public void multicastEvent(ApplicationEvent event) {
// event : ApplicationStartingEvent
multicastEvent(event, resolveDefaultEventType(event));
}
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// executor 为空
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
// 调用ApplicationListener
invokeListener(listener, event);
}
}
}
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClass());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
}
列举了上述的代码可能有些杂乱,我们从SpringApplicationRunListeners.starting()开始整理一下调用链,清晰一下流程
SpringApplicationRunListeners.starting()EventPublishingRunListener#startingSimpleApplicationEventMulticaster#multicastEvent()SimpleApplicationEventMulticaster#invokeListener(listener, event)doInvokeListener(listener, event)listener.onApplicationEvent(event)
本质上就是
EventPublishingRunListener#starting()方法发布了ApplicationStartingEvent事件,然后获取ApplicationListener列表并遍历执行ApplicationListener#onApplicationEvent(event)方法。
总结
我们通过SpringApplicationRunListeners的两个方法,理解了EventPublishingRunListener的创建逻辑,并探讨了SimpleApplicationEventMulticaster发布ApplicationStartingEvent事件的原理,接着剖析了SimpleApplicationEventMulticaster触发ApplicationListener列表依次监听ApplicationStartingEvent事件的流程。
Spring Boot这样的设计其实就是创建一个监听对象SpringApplicationRunListeners,这个监听对象内部封装了SpringApplicationRunListener的List对象,其实只包含EventPublishingRunListener对象;而EventPublishingRunListener内部有引入了SimpleApplicationEventMulticaster来发布事件,当事件发布后再触发ApplicationListener监听。其实就是自己发布事件再触发事件的监听,这是把所有的累活都一个人干了。