【spring】spring学习系列之十一:spring的事件监听
系列文章目录
文章目录
- 系列文章目录
- 前言
- 一、使用
- 二、整体流程
- 三、EventListenerMethodProcessor和DefaultEventListenerFactory
- 1.EventListenerMethodProcessor
- 2.DefaultEventListenerFactory
- 3.ApplicationListenerDetector
- 4.initApplicationEventMulticaster
- 5.registerListeners
- 6.SimpleApplicationEventMulticaster
- 四、事件发布过程
- 总结
前言
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 {// 监听特定类型的事件@EventListenerpublic 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;@Overridepublic 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 EventListenerMethodProcessorimplements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {}
1)BeanFactoryPostProcessor 是在容器执行refresh方法中的invokeBeanFactoryPostProcessors方法时调用,前面文章已经介绍过。看下代码
@Overridepublic 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实例化初始化都完成后执行的,前面文章也介绍过。看下这里的实现代码:
@Overridepublic 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 methodsConfigurableApplicationContext 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 retrievalBoolean 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 eventslogger.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类型@EventListenerpublic void handleString(String payload) {// 能接收 publishEvent("hello")}// 类型2:声明PayloadApplicationEvent泛型@EventListenerpublic 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 类型的事件,都需要对应的监听器才能处理