一、Spring是发布事件源码流程
1.1)首先我们自己写一个TulingApplicationListener 实现ApplicationListener接口,并且把该组件加入到容器中.
/**
* 创建一个监听器
*/
@Component
public class TulingApplicationListener implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("TulingApplicationListener 接受到了一个事件"+event);
}
}
然后我们自己又手动去发布一个事件。
public class MainClass {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
ctx.publishEvent(new ApplicationEvent("我手动发布了一个事件") {
@Override
public Object getSource() {
return super.getSource();
}
});
容器关闭也发布事件
ctx.close();
}
}
运行结果,这里我们也发现了当容器关闭的时候也会发布事件。
我拦截到了
TulingApplicationListener 接受到了一个事件org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@191beef: startup date [Sat Oct 09 15:03:27 CST 2021]; root of context hierarchy]
TulingApplicationListener 接受到了一个事件com.tuling.testapplicationlistener.MainClass$1[source=我手动发布了一个事件]
TulingApplicationListener 接受到了一个事件org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@191beef: startup date [Sat Oct 09 15:03:27 CST 2021]; root of context hierarchy]
1.2Spring事件发布源码解析
源码位置:org.springframework.context.support.AbstractApplicationContext#refresh
/**
* Create a new AnnotationConfigApplicationContext, deriving bean definitions
* from the given annotated classes and automatically refreshing the context.
* @param annotatedClasses one or more annotated classes,
* e.g. {@link Configuration @Configuration} classes
*/
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
// 这里面进行事件的注册与发布
refresh();
}
org.springframework.context.support.AbstractApplicationContext#initApplicationEventMulticaster,这里进行初始化事件多播器,我们的事件的多播器就是用来注册事件,以及执行事件的。
下面是注册多播器的源码,他首先先判断IOC容器中是否包含applicationEventMulticaster(事件多播器)的Bean的name,如果存在则创建一个applicationEventMulticaster的Bean存在在IOC容器总,bean的name为applicationEventMulticaster。
如果容器中不包含一个名为applicationEventMulticaster的多播器的组件,那么他就会创建一个SimpleApplicationEventMulticaster的多播器并注册到容器中去。
/**
* Initialize the ApplicationEventMulticaster.
* Uses SimpleApplicationEventMulticaster if none defined in the context.
* @see org.springframework.context.event.SimpleApplicationEventMulticaster
*/
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// /判断IOC容器中包含applicationEventMulticaster 事件多播器的Bean的name
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
// /创建一个applicationEventMulticaster的bean放在IOC 容器中,bean的name 为applicationEventMulticaster
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isDebugEnabled()) {
logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
//容器中不包含一个beanName 为applicationEventMulticaster的多播器组件
else {
创建一个SimpleApplicationEventMulticaster 多播器
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 + "]");
}
}
}
把容器中的监听器注册到多播器上去 源码解析。
- 首先我们会先去容器中把ApplicationListener的查找出来,然后注册到多播器上,这里一般都是一些系统的ApplicationListener.
- 其次就会去扫描我们实现ApplicationListener的组件然后注册到多播器。
- 这里小伙伴们可能就会发现,如果在我们多播器没有初始化的时候,那早期想发布事件该怎么办,所以第三Spring就想到了这一点,他第三步的时候就会发布早期堆积的事件。
/**
* Add beans that implement ApplicationListener as listeners.
* Doesn't affect other listeners, which can be added without being beans.
*/
protected void registerListeners() {
// 去容器中把applicationListener 捞取出来注册到多播器上去(系统的)
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 这里是扫描自己定义实现了的ApplicationListener的组件
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);
}
}
}
下面来看下他具体发布事件的源码,首先获取所有的监听器,然后看看Spring容器是否支持异步执行事件。
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();
// 看spring 容器中是否支持线程池 异步发送事件
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);
}
});
}
else {
invokeListener(listener, event);
}
}
}
点进去invokeListener,Spring命名有个习惯,真正干事情的method,一般都是以doxxxxx开头。
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);
}
}
// 真正去执行事件的method
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 调用对于listener的onApplicationEvent事件
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.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}