Spring事件监听流程分析【源码浅析】
一、简介
- Spring早期是通过实现ApplicationListener接口来定义监听事件,在spring4.2的时候开始我们可以通过@EventListener注解来定义监听事件,ApplicationListener接口定义如下:
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {/*** 处理Spring监听事件,监听 ApplicationEvent 及其下面的子事件* 这里的ApplicationListener接口相当于观察者模式中的观察者Obverse接口,* 且此处使用的是观察者模式的“推-拉”模型中的“拉”模型, 主题对象在通知观察者* 的时候,只传递少量信息。如果观察者需要更具体的信息, 由观察者主动到主题对* 象中获取,相当于是观察者从主题对象中拉数据。一般这种 模型的实现中,会把主* 题对 象自身通过update()方法传递给观察者,这样在观察 者需要获取数据的时候,* 就可以通过这个引用来获取了。* Handle an application event.* @param event the event to respond to*/void onApplicationEvent(E event);
}
- Spring为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式(拉模型);为的就是业务系统逻辑的解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听,监听具体的实现内容是什么,发布者的工作只是为了发布事件而已。
- 比如在我们的系统中,我们需要记录某一些比较重要方法的调用日志,我们就可以通过自定义注解+实现自定义监听事件即可。
- 本篇文章我们通过@EventListener注解来分析Spring的事件注册及监听流程
二、使用@EventListener注解
- 建立事件对象,当调用publishEvent方法是会通过这个bean对象找对应事件的监听。
package com.asiainfo.gridtask.event;import com.asiainfo.gridtask.entity.log.SysLog;
import org.springframework.context.ApplicationEvent;/*** 系统日志事件,ApplicationEvent相当于观察者模式中的Subject主题对象,Spring容器* 发布监听事件后,* @author Jack.Cheng* @date 2020/1/7 15:04**/
public class SysLogEvent extends ApplicationEvent {public SysLogEvent(SysLog sysLog) {super(sysLog);}
}
- 看一看SysLogEvent类的继承图,SysLogEvent继承至ApplicationEvent,ApplicationEvent 继承至EventObject,EventObject对象中定义了一个Object类型的source变量用于存放事件的消息。
- 新增对应的监听类
package com.asiainfo.gridtask.event;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.asiainfo.gridtask.common.constant.CommonConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;/*** @author Jack.Cheng* @date 2020/1/7 15:08**/
@Slf4j
@Component
public class SysLogListener {@EventListener(SysLogEvent.class)public void saveSysLog(SysLogEvent event) {log.info("收到调用日志信息:info:{}" , JSON.toJSONString(event));}
}
- 建立对应的测试类
package com.asiainfo.gridtask.controller;import com.asiainfo.gridtask.entity.log.SysLog;
import com.asiainfo.gridtask.event.SysLogEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author Jack.Cheng* @date 2020/4/7 16:34**/
@RestController
public class TestController {@Autowiredprivate ApplicationContext applicationContext;@GetMapping("testEvent.do")public void testEvent(){SysLog sysLog = new SysLog();sysLog.setLogId("123456789").setStaffCode("jack").setPhoneNo("13378224441");applicationContext.publishEvent(new SysLogEvent(sysLog));}
}
- 调用Restful接口后结果如下:
三、源码解析
- 在AnnotationConfigUtils#registerAnnotationConfigProcessors注册了EventListenerMethodProcessor 的BeanDefinition信息, 初始化SpringIOC容器的时候会将EventListenerMethodProcessor注册到容器中。
- AnnotationConfigUtils是在AnnotationConfigServletWebServerApplicationContext构造方法里被加载。AnnotationConfigServletWebServerApplicationContext,他是spring boot启动入口的重要类(我这里用的是spring boot所以是这个类),可以相当于用xml的ClassPathXmlApplicationContext。
AnnotationConfigUtils类/*** 内部管理@EventListener注解处理器的bean名称* The bean name of the internally managed @EventListener annotation processor.*/public static final String EVENT_LISTENER_PROCESSOR_BEAN_NAME ="org.springframework.context.event.internalEventListenerProcessor";public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {...........省略...............// 注册EventListenerMethodProcessor对象if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));}if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));}return beanDefs;}
- 注册的EventListenerMethodProcessor对象会在初始化非懒加载对象的时候执行它的afterSingletonsInstantiated方法。这里通过AbstractApplicationContext类的refresh() 方法中的 finishBeanFactoryInitialization(beanFactory) 去做初始化。
- AbstractApplicationContext#refresh()
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// 记录容器的启动时间、标记“已启动”状态、检查环境变量prepareRefresh();// 初始化BeanFactory容器(DefaultListableBeanFactory)、注册BeanDefinitionConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 beanprepareBeanFactory(beanFactory);try {// 扩展点,具体逻辑由子类去实现postProcessBeanFactory(beanFactory);// 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法invokeBeanFactoryPostProcessors(beanFactory);// 注册 BeanPostProcessor 的实现类registerBeanPostProcessors(beanFactory);// 初始化MessageSourceinitMessageSource();// 注册Spring事件派发多播器initApplicationEventMulticaster();// 扩展点,交由子类实现onRefresh();// 注册事件监听器registerListeners();// 初始化所有的 singleton beansfinishBeanFactoryInitialization(beanFactory);// 广播事件finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// 销毁已经初始化的的BeandestroyBeans();// 设置 'active' 状态cancelRefresh(ex);throw ex;}finally {// 清除缓存resetCommonCaches();}}
}
- 这里我们重点关注refresh()#finishBeanFactoryInitialization(beanFactory)#preInstantiateSingletons() 方法
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {// Initialize conversion service for this context.if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));}// Register a default embedded value resolver if no bean post-processor// (such as a PropertyPlaceholderConfigurer bean) registered any before:// at this point, primarily for resolution in annotation attribute values.if (!beanFactory.hasEmbeddedValueResolver()) {beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));}// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);for (String weaverAwareName : weaverAwareNames) {getBean(weaverAwareName);}// Stop using the temporary ClassLoader for type matching.beanFactory.setTempClassLoader(null);// Allow for caching all bean definition metadata, not expecting further changes.beanFactory.freezeConfiguration();// 初始化非懒加载对象beanFactory.preInstantiateSingletons();}
- DefaultListableBeanFactory#preInstantiateSingletons()
@Overridepublic void preInstantiateSingletons() throws BeansException {..........省略非必要代码...........// 将注册的beanDefinition类信息封装到集合中List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);..........省略非必要代码...........// 触发所有适用bean的初始化后回调 主要是afterSingletonsInstantiated方法for (String beanName : beanNames) {Object singletonInstance = getSingleton(beanName);/*** 处理SmartInitializingSingleton的实现类,调用其afterSingletonsInstantiated()方法,该方法* 会将带有EventListener注解的方法包装为ApplicationListenerMethodAdapter类,Spring容器发布* 事件后将通过多播器触发调用这个类的onApplicationEvent(ApplicationEvent event)方法,这个方法* 最终会通过反射的方式对应的调用我们加了EventListener注解的方法,最终完成事件的发布调用流程*/if (singletonInstance instanceof SmartInitializingSingleton) {final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {smartSingleton.afterSingletonsInstantiated();return null;}, getAccessControlContext());}else {// 调用afterSingletonsInstantiated方法(EventListenerMethodProcessor类)smartSingleton.afterSingletonsInstantiated();}}}}
- EventListenerMethodProcessor类图如下,这里可以看到其实现了SmartInitializingSingleton接口
- EventListenerMethodProcessor#afterSingletonsInstantiated,敲黑板,这里开始注册带有@EventListener注解的方法了
@Overridepublic void afterSingletonsInstantiated() {// 获取EventListenerFactory工厂类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 {type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);}catch (Throwable ex) {// An unresolvable bean type, probably from a lazy bean - let's ignore it.if (logger.isDebugEnabled()) {logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);}}if (type != null) {if (ScopedObject.class.isAssignableFrom(type)) {try {Class<?> targetClass = AutoProxyUtils.determineTargetClass(beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));if (targetClass != null) {type = targetClass;}}catch (Throwable ex) {// An invalid scoped proxy arrangement - let's ignore it.if (logger.isDebugEnabled()) {logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);}}}try {// 重点是这个方法处理BeanprocessBean(beanName, type);}catch (Throwable ex) {throw new BeanInitializationException("Failed to process @EventListener " +"annotation on bean with name '" + beanName + "'", ex);}}}}}
- EventListenerMethodProcessor#processBean,这里会将带有EventListener注解的方法包装为ApplicationListenerMethodAdapter类,Spring容器在发布事件后会通过多播器触发调用这个类的onApplicationEvent(ApplicationEvent event)方法,这个方法最终会通过反射的方式对应的调用我们加了EventListener注解的方法,最终完成整个事件的发布调用流程。
private void processBean(final String beanName, final Class<?> targetType) {if (!this.nonAnnotatedClasses.contains(targetType) && !isSpringContainerClass(targetType)) {Map<Method, EventListener> annotatedMethods = null;try {// 拿到使用了@EventListener注解的方法annotatedMethods = MethodIntrospector.selectMethods(targetType,(MethodIntrospector.MetadataLookup<EventListener>) method ->AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));}catch (Throwable ex) {// An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.if (logger.isDebugEnabled()) {logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);}}if (CollectionUtils.isEmpty(annotatedMethods)) {this.nonAnnotatedClasses.add(targetType);if (logger.isTraceEnabled()) {logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());}}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) {// 判断是否支持该方法 这里用的DefaultEventListenerFactory spring5.0.8 写死的返回trueif (factory.supportsMethod(method)) {// 获取类上标注了@EventListener注解的方法Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));// 将该类和方法包装为ApplicationListenerMethodAdapter对象ApplicationListener<?> applicationListener = factory.createApplicationListener(beanName, targetType, methodToUse);if (applicationListener instanceof ApplicationListenerMethodAdapter) {// 如果是ApplicationListenerMethodAdapter对象 就把context和evaluator传进去((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);}// 添加到ApplicationListener事件Set集合中去context.addApplicationListener(applicationListener);break;}}}if (logger.isDebugEnabled()) {logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +beanName + "': " + annotatedMethods);}}}
}// 封装ApplicationListenerMethodAdapter对象
public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {return new ApplicationListenerMethodAdapter(beanName, type, method);
}
- ApplicationListenerMethodAdapter类的UML图
- ApplicationListenerMethodAdapter类的属性及部分关键方法。
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {protected final Log logger = LogFactory.getLog(getClass());// 当前监听器在容器中类名,Spring容器可以通过beanName获取该类private final String beanName;// 监听器中被@EventListener注解修饰的方法private final Method method;private final Method targetMethod;private final AnnotatedElementKey methodKey;private final List<ResolvableType> declaredEventTypes;@Nullableprivate final String condition;private final int order;@Nullableprivate ApplicationContext applicationContext;@Nullableprivate EventExpressionEvaluator evaluator;.........省略不相关方法.........../*** 该方法是实现了ApplicationListener接口的onApplicationEvent方法,当ApplicationContext容器* publishEvent事件后,最后具体执行的方法,相当于观察者模式中的ConcreteObverse对象实现* Obverse接口的方法。*/@Overridepublic void onApplicationEvent(ApplicationEvent event) {processEvent(event);}/*** Process the specified {@link ApplicationEvent}, checking if the condition* match and handling non-null result, if any.*/public void processEvent(ApplicationEvent event) {// 解析ApplicationContext发布的事件参数信息Object[] args = resolveArguments(event);if (shouldHandle(event, args)) {// 通过反射的形式执行通过@EventListener注解修饰的方法Object result = doInvoke(args);if (result != null) {handleResult(result);}else {logger.trace("No result object given - no result to handle");}}}@Nullableprotected Object doInvoke(Object... args) {//获取@EventListener注解修饰方法所在的BeanObject bean = getTargetBean();//将@EventListener注解修饰方法的权限设置可访问ReflectionUtils.makeAccessible(this.method);try {//通过反射执行该方法return this.method.invoke(bean, args);}catch (IllegalArgumentException ex) {assertTargetBean(this.method, bean, args);throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);}catch (IllegalAccessException ex) {throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);}catch (InvocationTargetException ex) {// Throw underlying exceptionThrowable targetException = ex.getTargetException();if (targetException instanceof RuntimeException) {throw (RuntimeException) targetException;}else {String msg = getInvocationErrorMessage(bean, "Failed to invoke event listener method", args);throw new UndeclaredThrowableException(targetException, msg);}}}// 获取目标类protected Object getTargetBean() {Assert.notNull(this.applicationContext, "ApplicationContext must no be null");return this.applicationContext.getBean(this.beanName);}
}
- 最后面就是触发事件监听了AbstractApplicationContext#publishEvent
public abstract class AbstractApplicationContext extends DefaultResourceLoaderimplements ConfigurableApplicationContext {.........省略非必要代码........@Overridepublic void publishEvent(ApplicationEvent event) {publishEvent(event, null);}/*** Publish the given event to all listeners.* @param event the event to publish (may be an {@link ApplicationEvent}* or a payload object to be turned into a {@link PayloadApplicationEvent})* @param eventType the resolved event type, if known* @since 4.2*/protected void publishEvent(Object event, @Nullable ResolvableType eventType) {Assert.notNull(event, "Event must not be null");// Decorate event as an ApplicationEvent if necessaryApplicationEvent applicationEvent;if (event instanceof ApplicationEvent) {applicationEvent = (ApplicationEvent) event;}else {applicationEvent = new PayloadApplicationEvent<>(this, event);if (eventType == null) {eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();}}// Multicast right now if possible - or lazily once the multicaster is initializedif (this.earlyApplicationEvents != null) {this.earlyApplicationEvents.add(applicationEvent);}else {// 进入multicastEventgetApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);}// Publish event via parent context as well...if (this.parent != null) {if (this.parent instanceof AbstractApplicationContext) {((AbstractApplicationContext) this.parent).publishEvent(event, eventType);}else {this.parent.publishEvent(event);}}}
}
- SimpleApplicationEventMulticaster#multicastEvent->invokeListener->doInvokeListener
@Overridepublic void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));//获取所有监听器,遍历,广播事件for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {//如果自定义实现了SimpleApplicationEventMulticaster类,并设置了线程池//则通过线程池异步的广播事件Executor executor = getTaskExecutor();if (executor != null) {executor.execute(() -> invokeListener(listener, event));}else {//未实现线程池,同步的执行广播事件invokeListener(listener, event);}}}//invokeListener方法,调用此类的doInvokeListener方法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);}}@SuppressWarnings({"unchecked", "rawtypes"})private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {try {//由实现了ApplicationListener接口的类执行该方法,这里是//ApplicationListenerMethodAdapter类,该方法在上面已经详细讲解过了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;}}}
- 到这里整个事件监听的方法都已执行完毕,本篇内容为博主的第一篇博客,限于博主知识水平有限,如有错误欢迎大家及时指正,谢谢大家。
Spring事件监听流程分析【源码浅析】相关推荐
- Spring5源码 - 11 Spring事件监听机制_源码篇
文章目录 pre 事件监听机制的实现原理[观察者模式] 事件 ApplicationEvent 事件监听者 ApplicationEvent 事件发布者 ApplicationEventMultica ...
- Spring5源码 - 12 Spring事件监听机制_异步事件监听应用及源码解析
文章目录 Pre 实现原理 应用 配置类 Event事件 事件监听 EventListener 发布事件 publishEvent 源码解析 (反推) Spring默认的事件广播器 SimpleApp ...
- 监听返回app_基于 Redis 消息队列实现 Laravel 事件监听及底层源码探究
在 Laravel 中,除了使用 dispatch 辅助函数通过 Illuminate\Bus\Dispatcher 显式推送队列任务外,还可以通过事件监听的方式隐式进行队列任务推送,在这个场景下,事 ...
- Spring5源码 - 13 Spring事件监听机制_@EventListener源码解析
文章目录 Pre 概览 开天辟地的时候初始化的处理器 @EventListener EventListenerMethodProcessor afterSingletonsInstantiated 小 ...
- spring 事件监听
用一个简单的例子来实现spring事件监听的功能 这个例子主要功能是,记录那些用户是第一次登入系统,如果用户是第一次登入系统,则调用spring的事件监听,记录这些用户. 主要用到的spring的类和 ...
- Spring事件监听原理
1 简述Spring的生命周期 不论是Spring的监听机制原理还是Spring AOP的原理,都是依托于Spring的生命周期,所以要了解Spring的监听机制原理就需要先了解Spring的生命周期 ...
- Spring5源码 - 10 Spring事件监听机制_应用篇
文章目录 Spring事件概览 事件 自定义事件 事件监听器 基于接口 基于注解 事件广播器 Spring事件概览 Spring事件体系包括三个组件:事件,事件监听器,事件广播器 事件 Spring的 ...
- Struts流程分析+源码分析
1.初始化工作 读取配置---转换器-----读取插件 当struts-config.xml配置文件加载到内存,则会创建两个map:ActionConfigs,FromBeans.这两个map都交由M ...
- spring 扫描所有_自定义Spring事件监听机制
开头提醒一下大家: 尽管我简化了Spring源码搞了个精简版的Spring事件机制,但是没接触过Spring源码的朋友阅读起来还是有很大难度,请复制代码到本地,边Debug边看 既然要简化代码,所以不 ...
最新文章
- 使用Wireshark进行DNS协议解析
- Unix环境高级编程(二十一)数据库函数库
- 二进制的mysql怎么装_使用二进制演示MySQL安装步骤
- 【大牛疯狂教学】java程序员大专找不到工作
- openstack 重启mysql_突然断电导致mariadb数据库无法启动(openstack 命令无法使用)...
- MVC模式 在Java Web应用程序中的实现
- linux网站权限一直自动关闭,奇妙伞-解决SELinux对网站目录权限控制的不当的问题--网上摘抄集合,记录使用...
- 现在当兵有什么待遇复原以后_当兵多少年最好呢?这些关键点会影响在部队发展,很重要、很实用...
- 第五章 列表、元组和字符串[DDT书本学习 小甲鱼]【8】
- 玩转Spring Boot 集成Dubbo
- 外设、总线、接口概念辨析
- Subclipse更新地址
- PreScan快速入门到精通第三讲快速搭建第一个自动驾驶仿真模型
- visual studio 总是和搜狗输入法冲突
- android开发塔防游戏机,上手快又耐玩 五款Android平台塔防类游戏推荐
- Deepfake——深度造假视频在智能城市中的风险
- Python实现rosbag转换成video
- 纸质合同为什么要升级为电子合同?区别在哪?
- Mybatis方法入参处理
- 美国CPSIA关于玩具和儿童产品的测试要求,CPC证书要求