Spring Boot事件机制分析
Spring事件机制的四个组件:Event, Publisher, Listener, Multicaster. 类图如下:
spring_event.jpg
几个组件顾名思义,不多赘述.
对应的接口:
事件:ApplicationEvent
事件发布器:ApplicationEventPublisher
事件监听器:ApplicationListener
事件广播器:ApplicationEventMulticaster
在Spring Boot Application的启动代码中, 核心方法:refreshContext(), 这里完成了Spring Context个各种组件初始化:
AbstractApplicationContext.java
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
}
}
可以看到与时间相关的两行:initApplicationEventMulticaster和registerListeners
AbstractApplicationContext.java
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isDebugEnabled()) {
logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
"': using default [" + this.applicationEventMulticaster + "]");
}
}
}
如果有自己注册的ApplicationEventMulticaster会优先使用自定义广播器,否则就使用SimpleApplicationEventMulticaster
看一下SimpleApplicationEventMulticaster的核心方法:
SimpleApplicationEventMulticaster.java
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);
}
});
}
else {
invokeListener(listener, event);
}
}
}
看到这里, 我们注意到有一个getTaskExecutor, 而TaskExecutor是Spring提供的一个任务执行器(不懂的可以参考https://docs.spring.io/spring/docs/3.0.0.M4/reference/html/ch25s04.html), Spring会尝试使用TaskExecutor来执行这个事件的发布, 我们来看一下SimpleApplicationEventMulticaster的taskExecutor, 有这么一段注释:
Default is equivalent to {@link org.springframework.core.task.SyncTaskExecutor}
所以有些资料里面就会说事件广播是用SyncTaskExecutor同步执行的. 然鹅, 回到上面初始化广播器的代码, 注意这句:
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
这是一个新new出来的广播器, 而且从来没有被调用过setTaskExecutor, 所以实际上根本没用使用taskExecutor. 但最终结果是一样的, 是同步广播事件到所有的Listener. 如果想要异步广播怎么办? 这里就会用到上面提到的自定义广播器了, 自定义一个Multicaster使用AsyncTaskExecutor就可以了.
广播器到此就初始化完成了, 下面开始注册Listeners:
AbstractApplicationContext.java
protected void registerListeners() {
// Register statically specified listeners first.
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// Publish early application events now that we finally have a multicaster...
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
第一步加载静态定义的Listeners, 这些Listeners从哪来的? 回头看一下启动代码:
SpringApplication.java
SpringApplicationRunListeners listeners = getRunListeners(args);
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
SpringApplicationRunListener接口规定了SpringBoot的生命周期,在各个生命周期广播相应的事件,调用实际的ApplicationListener类。从上面代码可以看到, 他是最先加载到ApplicationContext里的. 也最先被注册到广播器中
接下来就是获取所有ApplicationListener实现类了, 让我们可以方便的使用事件机制来做自己的事情. 只需要实现ApplicationListener接口, 就可以获取到所有事件通知, 所以注意做好事件过滤, 只处理自己关心的事件.
最后还有EventPublisher, 其实跟Multicaster差不多, 从最上面的类图也能看出来, Multicaster其实也是一个Publisher, 所以就不再贴代码了.
Spring事件机制的分析到这里就分析完毕了.