系列文章目录
文章目录
前言
Spring框架的事件机制(ApplicationEvent)提供了一种组件间通信的方式,允许应用程序的不同部分通过发布-订阅模式进行解耦交互。
一、使用
- 先定义事件
public class MyCustomEvent {
private String message;
public MyCustomEvent(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
- 注册事件监听器
这里是通过@EventListener的方式,也可以通过实现ApplicationListener接口的方式
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class MyEventListener {
// 监听特定类型的事件
@EventListener
public void handleMyEvent(MyCustomEvent event) {
System.out.println("Received MyCustomEvent - " + event.getMessage());
}
// 监听多个事件类型
@EventListener({AnotherEvent.class, YetAnotherEvent.class})
public void handleMultipleEvents(Object event) {
if (event instanceof AnotherEvent) {
System.out.println("Handling AnotherEvent");
} else if (event instanceof YetAnotherEvent) {
System.out.println("Handling YetAnotherEvent");
}
}
// 带条件的事件监听
@EventListener(condition = "#event.message.startsWith('important')")
public void handleImportantEvents(MyCustomEvent event) {
System.out.println("Received IMPORTANT event - " + event.getMessage());
}
}
- 发布事件
利用ApplicationContext发布事件,因为ApplicationContext有事件广播器
@Service
public class EventPublisherService implements ApplicationContextAware{
private ConfigurableApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void publishEvent(String message) {
MyCustomEvent event = new MyCustomEvent(message);
applicationContext.publishEvent(event);
}
}
二、整体流程
回顾一下spring的启动流程
- 在构造方法中,初始化了6个重要的BeanDefinition,其中有2个是EventListenerMethodProcessor和DefaultEventListenerFactory,之前介绍过这两个与@EventListener注解有关。
- 在refresh方法中,registerBeanPostProcessors这一步注册了ApplicationListenerDetector(检测bean是否为监听器类型),initApplicationEventMulticaster这一步初始化了SimpleApplicationEventMulticaster(事件广播器)
- 在refresh方法中,registerListeners这一步将所有的监听器注册到事件广播器中
我们知道了spring事件监听的相关组件,再来看看每个组件的具体功能
三、EventListenerMethodProcessor和DefaultEventListenerFactory
1.EventListenerMethodProcessor
EventListenerMethodProcessor实现了两个重要的接口BeanFactoryPostProcessor 和SmartInitializingSingleton
public class EventListenerMethodProcessor
implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
}
1)BeanFactoryPostProcessor 是在容器执行refresh方法中的invokeBeanFactoryPostProcessors方法时调用,前面文章已经介绍过。看下代码
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
List<EventListenerFactory> factories = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(factories);
this.eventListenerFactories = factories;
}
就是在容器中找到类型为EventListenerFactory的bean,然后设置到eventListenerFactories 这个属性中,而容器中正好在构造阶段注册了DefaultEventListenerFactory这个BeanDefinition。注意,eventListenerFactories 是一个集合,也就是说我们也可以自己注册类型为EventListenerFactory的bean。当然我们现在只分析DefaultEventListenerFactory即可。
2)SmartInitializingSingleton是在所有的bean实例化初始化都完成后执行的,前面文章也介绍过。看下这里的实现代码:
@Override
public void afterSingletonsInstantiated() {
ConfigurableListableBeanFactory beanFactory = this.beanFactory;
Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
if (!ScopedProxyUtils.isScopedTarget(beanName)) {
Class<?> type = null;
try {
//如果这个BeanDefinition是代理对象,使用被代理的class。因为被代理的class才有@EventListener注解
type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
}
catch (Throwable ex) {
...
}
if (type != null) {
...
try {
processBean(beanName, type);
}
catch (Throwable ex) {
...
}
}
}
}
}
可以看到就是遍历所有的beanName,调用processBean方法
private void processBean(final String beanName, final Class<?> targetType) {
if (!this.nonAnnotatedClasses.contains(targetType) &&
AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
!isSpringContainerClass(targetType)) {
Map<Method, EventListener> annotatedMethods = null;
try {
//查找Class上所有被@EventListener注解的方法
annotatedMethods = MethodIntrospector.selectMethods(targetType,
(MethodIntrospector.MetadataLookup<EventListener>) method ->
AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
}
catch (Throwable ex) {
。。。
}
}
if (CollectionUtils.isEmpty(annotatedMethods)) {
this.nonAnnotatedClasses.add(targetType);
。。。
}
else {
// Non-empty set of methods
ConfigurableApplicationContext context = this.applicationContext;
Assert.state(context != null, "No ApplicationContext set");
List<EventListenerFactory> factories = this.eventListenerFactories;
Assert.state(factories != null, "EventListenerFactory List not initialized");
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {//判断工厂类是否支持该方法
Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
//利用工厂生成一个ApplicationListener实例
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
}
//将生成的ApplicationListener实例添加到Spring的applicationListeners中,后续会注册到事件广播器上
context.addApplicationListener(applicationListener);
break;
}
}
}
。。。
}
}
}
逻辑如下:
a. 查找Class上所有被@EventListener注解的方法
b. 如果有被@EventListener注解的方法,遍历所有的EventListenerFactory,找到能处理这个方法的EventListenerFactory (适配器模式),利用EventListenerFactory工厂将该方法生成一个ApplicationListener实例。
可以通过@EventListener注解的属性增加一些功能,比如前面例子中的通过condition属性判断是不是要处理这个事件,这里就不展开了
c. 将生成的ApplicationListener实例添加到Spring的applicationListeners中,后续会注册到事件广播器上
2.DefaultEventListenerFactory
上面已经介绍了,这个类就是将被@EventListener注解的方法生成一个ApplicationListener实例。不展开了
3.ApplicationListenerDetector
实现了MergedBeanDefinitionPostProcessor
class ApplicationListenerDetector implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor {
}
MergedBeanDefinitionPostProcessor 有2个扩展点,一个是在createBeanInstance之后执行postProcessMergedBeanDefinition方法,这里就是判断是否为单例bean
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (ApplicationListener.class.isAssignableFrom(beanType)) {
this.singletonNames.put(beanName, beanDefinition.isSingleton());
}
}
另一个是在初始化后执行postProcessAfterInitialization方法:就是判断如果这个bean实现了ApplicationListener接口,且是单例bean,添加到Spring的applicationListeners中,后续会注册到事件广播器上
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof ApplicationListener) {
// potentially not detected as a listener by getBeanNamesForType retrieval
Boolean flag = this.singletonNames.get(beanName);
if (Boolean.TRUE.equals(flag)) {
// singleton bean (top-level or inner): register on the fly
//添加到Spring的applicationListeners中,后续会注册到事件广播器上
this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
}
else if (Boolean.FALSE.equals(flag)) {
if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
// inner bean with other scope - can't reliably process events
logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
"but is not reachable for event multicasting by its containing ApplicationContext " +
"because it does not have singleton scope. Only top-level listener beans are allowed " +
"to be of non-singleton scope.");
}
this.singletonNames.remove(beanName);
}
}
return bean;
}
4.initApplicationEventMulticaster
1)从容器中找beanName为applicationEventMulticaster的bean,如果存在,将其设置为applicationEventMulticaster
2)如果不存在,创建一个默认的SimpleApplicationEventMulticaster,设置为applicationEventMulticaster
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.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
5.registerListeners
遍历applicationListeners中的ApplicationListener,注册到ApplicationEventMulticaster中,这里才算是真正注册上了
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
6.SimpleApplicationEventMulticaster
注册ApplicationListener,就是将ApplicationListener放到内部类defaultRetriever的applicationListeners属性中
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.defaultRetriever) {
// Explicitly remove target for a proxy, if registered already,
// in order to avoid double invocations of the same listener.
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
四、事件发布过程
上面已经介绍了监听器的注册,接下来看看事件发布过程
前面的例子中,我们是通过ApplicationContext的publishEvent方法来发布事件的
有2个方法,分别用来发布ApplicationEvent类型的事件和非ApplicationEvent 类型的事件
//发布ApplicationEvent类型的事件
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
}
//发布非ApplicationEvent 类型的事件
public void publishEvent(Object event) {
publishEvent(event, null);
}
我们主要看发布ApplicationEvent类型的事件,通过getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);调用SimpleApplicationEventMulticaster的multicastEvent方法
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
//找到能处理该事件的监听器,遍历
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
//如果执行器不为空,用执行器调用监听器的onApplicationEvent方法
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
//如果执行器为空,直接调用监听器的onApplicationEvent方法
invokeListener(listener, event);
}
}
}
1)找到能处理该事件的监听器,遍历监听器
2)如果执行器不为空,用执行器调用监听器的onApplicationEvent方法。
这里是为了使用线程池来异步执行,而SimpleApplicationEventMulticaster的executor是为空的,那怎么异步呢?前面讲initApplicationEventMulticaster时,如果容器没有广播器才创建默认的SimpleApplicationEventMulticaster,那我们自己定义一个广播器继承SimpleApplicationEventMulticaster,并且设置一个线程池,那不就可以异步了吗
3)如果执行器为空,直接调用监听器的onApplicationEvent方法
这种情况就同步执行
getApplicationListeners方法有点复杂,因为为了支持非ApplicationEvent 类型的事件,做了一些包装
这里只简单介绍一下非ApplicationEvent 类型的事件的用法
@Component
public class MyListeners {
// 类型1:直接声明payload类型
@EventListener
public void handleString(String payload) {
// 能接收 publishEvent("hello")
}
// 类型2:声明PayloadApplicationEvent泛型
@EventListener
public void handlePayloadEvent(PayloadApplicationEvent<String> event) {
String payload = event.getPayload();
// 能接收 publishEvent("hello")
}
}
总结
- 监听器需要注册到ApplicationEventMulticaster后才能监听事件,有2中注册方式
1)在所有的bean实例化初始化都完成后,通过EventListenerMethodProcessor查找@EventListener注解的方法,将其生成ApplicationLister对象,然后注册到ApplicationEventMulticaster中
2)通过ApplicationListenerDetector这个BPP,在bean的生命周期中执行初始化后方法postProcessAfterInitialization,如果这个bean实现了ApplicationListener接口,且是单例bean,注册到ApplicationEventMulticaster中 - 发布事件时,找到能处理该事件的所有监听器,遍历监听器,逐个执行监听器的onApplicationEvent方法。如果要异步执行,必须给广播器设置线程池。
- 事件分为ApplicationEvent类型的事件和非ApplicationEvent 类型的事件,都需要对应的监听器才能处理