# 【SpringBoot】SpringBoot 下 @EventListener 注解使用及源码解析
原文链接,侵删:【https://blog.csdn.net/baidu_19473529/article/details/97646739】
# 一、简介
@EventListener 是一种事件驱动编程在 spring4.2 的时候开始有的,早期可以实现 ApplicationListener 接口,想了解下 ApplicationListener 的可以参考下这篇文章 https://blog.csdn.net/baidu_19473529/article/details/86683365Spring 为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式;为的就是业务系统逻辑的解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听,监听具体的实现内容是什么,发布者的工作只是为了发布事件而已。
比如我们做一个电商系统,用户下单支付成功后,我们一般要发短信或者邮箱给用户提示什么的,这时候就可以把这个通知业务做成一个单独事件监听,等待通知就可以了;把它解耦处理。
# 二、使用 @EventListener 注解
建立事件对象,当调用 publishEvent 方法是会通过这个 bean 对象找对应事件的监听。AddDataEvent.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 package com.rw.article.pay.event.bean; import org.springframework.context.ApplicationEvent; /** * @author Zhou Zhong Qing * @Title: ${file_name} * @Package ${package_name} * @Description: 新增mongodb数据事件 * @date 2018/10/18 16:26 */ public class AddDataEvent extends ApplicationEvent { public AddDataEvent(Object source) { super(source); } public AddDataEvent(Object source, Class clz, Object data) { super(source); this.clz = clz; this.data = data; } public AddDataEvent(Object source, Class clz, Object data, String modelName, String userAgent) { super(source); this.clz = clz; this.data = data; this.modelName = modelName; this.userAgent = userAgent; } /** 要更新的表对象 **/ private Class clz; /** 操作的数据**/ private Object data; /** 模块名称**/ private String modelName; /** 浏览器标识 **/ private String userAgent; public Class getClz() { return clz; } public void setClz(Class clz) { this.clz = clz; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } public String getModelName() { return modelName; } public void setModelName(String modelName) { this.modelName = modelName; } public String getUserAgent() { return userAgent; } public void setUserAgent(String userAgent) { this.userAgent = userAgent; } }
对应的监听 AddDataEventListener .java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package com.rw.article.pay.event.listener; import com.alibaba.fastjson.JSON; import com.rw.article.pay.event.bean.AddDataEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; /** * @author Zhou Zhong Qing * @Title: ${file_name} * @Package ${package_name} * @Description: 新增数据的事件监听 * @date 2018/10/18 16:29 */ @Component public class AddDataEventListener { private static Logger log = LoggerFactory.getLogger(AddDataEventListener.class); /* * 在AnnotationConfigUtils#registerAnnotationConfigProcessors注册了BeanDefinition 对应的是EventListenerMethodProcessor对象 , AnnotationConfigUtils在AnnotationConfigServletWebServerApplicationContext构造方法里被加载 * */ /** * DefaultListableBeanFactory#中preInstantiateSingletons -> (beanName为org.springframework.context.event.internalEventListenerProcessor时得到EventListenerMethodProcessor)EventListenerMethodProcessor#afterSingletonsInstantiated this.processBean(factories, beanName, type) * 然后把要执行的方法封装为ApplicationListenerMethodAdapter -> 添加到listener中 AbstractApplicationEventMulticaster#addApplicationListener * */ // 该方法在 ApplicationListenerMethodAdapter 利用反射执行 /** * 处理新增数据的事件 **/ @EventListener public void handleAddEvent(AddDataEvent event) { log.info("发布的data为:{} ", JSON.toJSONString(event)); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package com.rw.article.pay.action; import com.rw.article.pay.event.bean.AddDataEvent; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import javax.annotation.Resource; /** * @author Zhou Zhong Qing * @Title: ${file_name} * @Package ${package_name} * @Description: 测试的controller * @date 2019/7/24 17:13 */ @Controller @RequestMapping("/test") public class TestController { @Resource private ApplicationContext applicationContext; @ResponseBody @RequestMapping("/testListener") public String testListener(){ applicationContext.publishEvent(new AddDataEvent(this,TestController.class,"test")); return "success"; } }
结果是能够监听到的
如果要使用异步加上 @EnableAsync
注解,方法上加 @Async
注解,如下 spring boot 项目配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @SpringBootApplication @EnableAsync public class XApplication{ public static void main(String[] args) { ConfigurableApplicationContext run = new SpringApplicationBuilder(XApplication.class).web(true ).run(args); run.publishEvent("test" ); } } @Async @EventListener public void test (String wrapped){ System.out.println("当前线程 " +Thread.currentThread().getName()); System.out.println(wrapped); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Configuration public class GenericConfiguration { @Bean public Executor taskExecutor () { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //核心线程数:线程池创建时候初始化的线程数 //最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程 //缓冲队列:用来缓冲执行任务的队列 //允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁 //线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池 //线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务 executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(20); executor.setKeepAliveSeconds(60); executor.setThreadNamePrefix("taskExecutor-" ); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); return executor; } }
# 三、源码解析
原理还得从 org.springframework.context.event.internalEventListenerProcessor
说起。
在 AnnotationConfigUtils#registerAnnotationConfigProcessors 注册了 BeanDefinition 对应的是 EventListenerMethodProcessor 对象 , 而 AnnotationConfigUtils 是在 AnnotationConfigServletWebServerApplicationContext 构造方法里被加载。这里要提一下 AnnotationConfigServletWebServerApplicationContext,他是 spring boot 启动入口的重要类 (我这里用的是 spring boot 所以是这个类), 可以相当于以前用 xml 的 ClassPathXmlApplicationContext。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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)); } ........................... return beanDefs; }
注册的 EventListenerMethodProcessor 对象会在初始化非懒加载对象的时候运行它的 afterSingletonsInstantiated 方法。
AbstractApplicationContext#finishBeanFactoryInitialization
1 2 3 4 5 6 protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { ............. // 初始化非懒加载对象 beanFactory.preInstantiateSingletons(); }
DefaultListableBeanFactory#preInstantiateSingletons
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Override public void preInstantiateSingletons() throws BeansException { .................. // 触发所有适用bean的初始化后回调 主要是afterSingletonsInstantiated方法 for (String beanName : beanNames) { //如果beanName传入org.springframework.context.event.internalEventListenerProcessor 因为已经上面代码已经初始化,将从缓存中得到一个EventListenerMethodProcessor对象 Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { smartSingleton.afterSingletonsInstantiated(); return null; }, getAccessControlContext()); } else { // 调用其afterSingletonsInstantiated方法 smartSingleton.afterSingletonsInstantiated(); } } } }
EventListenerMethodProcessor#afterSingletonsInstantiated
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 @Override public void afterSingletonsInstantiated() { List<EventListenerFactory> factories = getEventListenerFactories(); ConfigurableApplicationContext context = getApplicationContext(); String[] beanNames = context.getBeanNamesForType(Object.class); for (String beanName : beanNames) { if (!ScopedProxyUtils.isScopedTarget(beanName)) { Class<?> type = null; try { type = AutoProxyUtils.determineTargetClass(context.getBeanFactory(), 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( context.getBeanFactory(), 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 { // 重点是这个方法 处理bean processBean(factories, beanName, type); } catch (Throwable ex) { throw new BeanInitializationException("Failed to process @EventListener " + "annotation on bean with name '" + beanName + "'", ex); } } } } }
EventListenerMethodProcessor#processBean; 这里有一个重要的类就是 ApplicationListenerMethodAdapter,spring 把加入了 @EventListener 注解的方法封装进 ApplicationListenerMethodAdapter 对象里,然后我们 publishEvent 方法是,其实是调用的对应的 ApplicationListenerMethodAdapter, 然后里面是执行这个方法,这里可以看下 ApplicationListenerMethodAdapter 类的属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 public class ApplicationListenerMethodAdapter implements GenericApplicationListener { protected final Log logger = LogFactory.getLog(getClass()); private final String beanName; private final Method method; private final Method targetMethod; private final AnnotatedElementKey methodKey; private final List<ResolvableType> declaredEventTypes; @Nullable private final String condition; private final int order; @Nullable private ApplicationContext applicationContext; @Nullable private EventExpressionEvaluator evaluator; .................................. } protected void processBean( final List<EventListenerFactory> factories, final String beanName, final Class<?> targetType) { if (!this.nonAnnotatedClasses.contains(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 methods ConfigurableApplicationContext context = getApplicationContext(); for (Method method : annotatedMethods.keySet()) { for (EventListenerFactory factory : factories) { // 判断是否支持该方法 这里用的DefaultEventListenerFactory spring5.0.8 写死的返回true if (factory.supportsMethod(method)) { //选择方法 beanName 这里是AddDataEventListener的beanName 默认是addDataEventListener 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); } } } }
后面就是触发事件监听了 AbstractApplicationContext#publishEvent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @Override public void publishEvent(ApplicationEvent event) { publishEvent(event, null); } protected void publishEvent(Object event, @Nullable ResolvableType eventType) { .............................. // Multicast right now if possible - or lazily once the multicaster is initialized if (this.earlyApplicationEvents != null) { this.earlyApplicationEvents.add(applicationEvent); } else { // 进入multicastEvent getApplicationEventMulticaster().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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) { try { listener.onApplicationEvent(event); } catch (ClassCastException ex) { String msg = ex.getMessage(); if (msg == null || matchesClassCastMessage(msg, event.getClass().getName())) { // 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; } } }
ApplicationListenerMethodAdapter#onApplicationEvent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Override public void onApplicationEvent(ApplicationEvent event) { processEvent(event); } ApplicationListenerMethodAdapter#processEvent public void processEvent(ApplicationEvent event) { Object[] args = resolveArguments(event); if (shouldHandle(event, args)) { // 执行真正的方法 Object result = doInvoke(args); if (result != null) { handleResult(result); } else { logger.trace("No result object given - no result to handle"); } } }
ApplicationListenerMethodAdapter#doInvoke
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 protected Object doInvoke(Object... args) { Object bean = getTargetBean(); 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 exception Throwable 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); } } }
ApplicationListenerMethodAdapter#getTargetBean
1 2 3 4 protected Object getTargetBean() { Assert.notNull(this.applicationContext, "ApplicationContext must no be null"); return this.applicationContext.getBean(this.beanName); }
至此执行这个事件监听的方法执行完毕。如果文字有误的地方,希望批评指正,感谢您的观看。
# 关于我
Brath 是一个热爱技术的 Java 程序猿,公众号「InterviewCoder」定期分享有趣有料的精品原创文章!
非常感谢各位人才能看到这里,原创不易,文章如果有帮助可以关注、点赞、分享或评论,这都是对我的莫大支持!