上篇文章从springboot应用的启动开始说起,分析完了SpringApplication对象的初始化流程
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
这篇文章开始分析后面的run方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
Banner printedBanner = this.printBanner(environment);
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
限于篇幅,本篇主要分析到这行listeners.starting结束,也就是先简单介绍下springboot初始化过程的事件发布机制,以及在springboot项目开始启动时候的一个扩展点
前面的StopWatch主要是记录下启动的时间,调用start就会获取系统时间赋给startTime,结束的时候再调下stop,计算系统启动耗时;
this.configureHeadlessProperty()主要是设置启动模式为headless,在缺少外接设备(显示屏、键盘)等的环境启动
这些都不是重点,我们主要关注有关listener的两行代码
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
首先进入getRunListeners方法
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
可以看到一个熟悉的方法getSpringFactoriesInstances,上篇文章我们分析过,这个方法的主要作用就是从META-INF/spring.factories中找到指定类型(这里即SpringApplicationRunListener)的实现,并实例化,只是不同的是,这里传入了一个class[],并指定了参数,也就是指定了实例化时要调用的有参构造器,第一个参数就是上篇文章着重介绍的SpringApplication对象,第二个参数是args,也就是main方法的入参
通过debug,发现在spring.factories中,只加载到了一个,具体类型为EventPublishingRunListener
位置在spring-boot下的META-INF/spring.factories中
进入这个类,先观察下它指定的构造方法
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;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
Iterator var3 = application.getListeners().iterator();
while(var3.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var3.next();
this.initialMulticaster.addApplicationListener(listener);
}
}
......
......
将SpringApplication对象和启动参数存储起来,并初始化了一个事件多播器
然后调用了SpringApplication的getListeners方法,之前分析过,这个listeners中存储的就是从spring.factories文件中找到的ApplicationListener,然后添加到事件多播器中,也就是说,此时这个事件多播器中已经有了一些监听者,可以向他们发布事件了
public void addApplicationListener(ApplicationListener<?> listener) {
Object var2 = this.retrievalMutex;
synchronized(this.retrievalMutex) {
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
实例化完成后,回过头来看下这个SpringApplicationRunListeners的构造方法
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
this.listeners = new ArrayList(listeners);
}
就是把找到的SpringApplicationRunListener存储在变量listeners中,目前是只有一个EventPublishingRunListener,其内部有一个事件多播器,存储了SpringAapplication对象初始化时找到的ApplicationListener列表
到此第一行结束,再看第二行listeners.starting()
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
public void starting() {
Iterator var1 = this.listeners.iterator();
while(var1.hasNext()) {
SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next();
listener.starting();
}
}
循环listeners,调用其starting方法
这里只有一个,就可以简单看成是调用EventPublishingRunListener的starting方法
看下这个方法的实现
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
public void multicastEvent(ApplicationEvent event) {
this.multicastEvent(event, this.resolveDefaultEventType(event));
}
通过多播器发布了一个事件ApplicationStartingEvent,这个多播器在初始化后,就把SpringApplication中的listeners都注册给它了,然后就可以从这些listeners中,找到对当前事件感兴趣的监听者
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
Iterator var4 = this.getApplicationListeners(event, type).iterator();
while(var4.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var4.next();
Executor executor = this.getTaskExecutor();
if (executor != null) {
executor.execute(() -> {
this.invokeListener(listener, event);
});
} else {
this.invokeListener(listener, event);
}
}
}
进入getApplicationListeners方法,其中Collection<ApplicationListener<?>> listeners = this.retrieveApplicationListeners(eventType, sourceType, retriever) 这行代码就通过事件类型找到了匹配的监听者
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
Object source = event.getSource();
Class<?> sourceType = source != null ? source.getClass() : null;
AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType);
AbstractApplicationEventMulticaster.ListenerRetriever retriever = (AbstractApplicationEventMulticaster.ListenerRetriever)this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
} else if (this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader))) {
Object var7 = this.retrievalMutex;
synchronized(this.retrievalMutex) {
retriever = (AbstractApplicationEventMulticaster.ListenerRetriever)this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
} else {
retriever = new AbstractApplicationEventMulticaster.ListenerRetriever(true);
Collection<ApplicationListener<?>> listeners = this.retrieveApplicationListeners(eventType, sourceType, retriever);
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
}
} else {
return this.retrieveApplicationListeners(eventType, sourceType, (AbstractApplicationEventMulticaster.ListenerRetriever)null);
}
}
具体寻找的过程,先遍历所有的listener,调用supportEvent方法
supportsEvent方法的实现,如果监听器是GenericApplicationListener类型,就已经实现了supportsEventType方法,后面可以直接调用该方法判断是否支持当前事件,如果不是GenericApplicationListener类型,就把事件封装成GenericApplicationListenerAdapter,然后调用封装后的Adapter的supportsEventType方法
protected boolean supportsEvent(ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
GenericApplicationListener smartListener = listener instanceof GenericApplicationListener ? (GenericApplicationListener)listener : new GenericApplicationListenerAdapter(listener);
return ((GenericApplicationListener)smartListener).supportsEventType(eventType) && ((GenericApplicationListener)smartListener).supportsSourceType(sourceType);
}
看下封装成Adapter的逻辑,在Adapter的构造函数中,把当前的监听器赋给变量delegate ,然后通过resolveDeclaredEventType完成对监听事件类型的解析
public GenericApplicationListenerAdapter(ApplicationListener<?> delegate) {
Assert.notNull(delegate, "Delegate listener must not be null");
this.delegate = delegate;
this.declaredEventType = resolveDeclaredEventType(this.delegate);
}
resolveDeclaredEventType方法
@Nullable
private static ResolvableType resolveDeclaredEventType(ApplicationListener<ApplicationEvent> listener) {
ResolvableType declaredEventType = resolveDeclaredEventType(listener.getClass());
if (declaredEventType == null || declaredEventType.isAssignableFrom(ApplicationEvent.class)) {
Class<?> targetClass = AopUtils.getTargetClass(listener);
if (targetClass != listener.getClass()) {
declaredEventType = resolveDeclaredEventType(targetClass);
}
}
return declaredEventType;
}
调用了同名方法
@Nullable
static ResolvableType resolveDeclaredEventType(Class<?> listenerType) {
ResolvableType eventType = (ResolvableType)eventTypeCache.get(listenerType);
if (eventType == null) {
eventType = ResolvableType.forClass(listenerType).as(ApplicationListener.class).getGeneric(new int[0]);
eventTypeCache.put(listenerType, eventType);
}
return eventType != ResolvableType.NONE ? eventType : null;
}
最终是通过as方法,转化为ApplicationListener并取其泛型作为事件类型
说白了就是到类的继承结构中,找到ApplicationListener< T >,取T作为要监听的事件类型
public ResolvableType as(Class<?> type) {
if (this == NONE) {
return NONE;
} else {
Class<?> resolved = this.resolve();
if (resolved != null && resolved != type) {
ResolvableType[] var3 = this.getInterfaces();
int var4 = var3.length;
for(int var5 = 0; var5 < var4; ++var5) {
ResolvableType interfaceType = var3[var5];
ResolvableType interfaceAsType = interfaceType.as(type);
if (interfaceAsType != NONE) {
return interfaceAsType;
}
}
return this.getSuperType().as(type);
} else {
return this;
}
}
}
比如我们自己定义一个监听器
public class MyListener implements ApplicationListener<ApplicationEvent> {
那么最终取到的就是泛型中的ApplicationEvent
然后看下这个GenericApplicationListenerAdapter的supportsEventType方法的实现
public boolean supportsEventType(ResolvableType eventType) {
if (this.delegate instanceof SmartApplicationListener) {
Class<? extends ApplicationEvent> eventClass = eventType.resolve();
return eventClass != null && ((SmartApplicationListener)this.delegate).supportsEventType(eventClass);
} else {
return this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType);
}
}
如果监听器是SmartApplicationListener类型,则调用监听器自己的supportsEventType方法,否则就看声明的事件类型(即上面ApplicationEvent< T >的类型)是否是当前事件或当前事件的父类
到此针对判断监听器是否该处理某个事件,做个小结
- 如果监听器的类型是GenericApplicationListener类型,则直接调用它的supportsEventType方法
- 如果不是GenericApplicationListener类型,则先包装成GenericApplicationListenerAdapter,在包装的过程中,获取类声明中的事件类型ApplicationListener< T >作为要监听的事件类型
- 如果监听器类型是SmartApplicationListener,则调用它的supportsEventType方法
- 判断 T 是否是当前事件或当前事件的父类
再附上一张最初的10个Listener的继承结构,以及各个监听器感兴趣的事件
通过supportsEventType判断支持当前事件类型后,再调用supportsSourceType方法,该方法默认返回的就是true,监听器也可以重写该方法,指定自己关注的事件源
public interface GenericApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
boolean supportsEventType(ResolvableType var1);
default boolean supportsSourceType(@Nullable Class<?> sourceType) {
return true;
}
default int getOrder() {
return 2147483647;
}
}
通过debug,可以看到对ApplicationStartingEvent感兴趣的监听者有4个
(ApplicationStartingEvent继承自SpringApplicationEvent,而SpringApplicationEvent又继承自ApplicationEvent,结合上面分析的流程以及监听器的类图,就不难知道为什么是这4个了)
- DelegatingApplicationListener
- LoggingApplicationListener
- LiquibaseServiceLocatorApplicationListener
- BackgroundPreinitializer
本文只介绍事件发布机制的大概原理,至于上面4个监听者,在ApplicationStartingEvent事件中做了哪些处理,我们后续再分析
回到之前的代码,对找到的监听者调用invokeListener,最终调用它的onApplicationEvent方法
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = this.getErrorHandler();
if (errorHandler != null) {
try {
this.doInvokeListener(listener, event);
} catch (Throwable var5) {
errorHandler.handleError(var5);
}
} else {
this.doInvokeListener(listener, event);
}
}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
} catch (ClassCastException var6) {
String msg = var6.getMessage();
if (msg != null && !this.matchesClassCastMessage(msg, event.getClass())) {
throw var6;
}
Log logger = LogFactory.getLog(this.getClass());
if (logger.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, var6);
}
}
}
扩展点ApplicationStartingEvent
假如你想在springboot项目启动的时候,做一些初始化,就可以自己实现一个监听器,监听这个ApplicationStartingEvent的发布
比如新建一个监听者MyApplicationStartListener
public class MyApplicationStartListener implements ApplicationListener<ApplicationStartingEvent> {
@Override
public void onApplicationEvent(ApplicationStartingEvent applicationStartingEvent) {
System.out.println("=====项目开始启动=====");
//doSomething
}
}
然后在项目中新建/META-INF/spring.factories文件,把这个自定义的监听器配置进去
启动项目,可以看到在springboot项目最初启动的时候就打印了日志,这也可以看作是springboot给我们提供的一个扩展点