在上文中讲了Spring的事件监听机制,流程是:定义事件、监听器,发布事件,控制台输出监听到的事件内容。

  在上文的扩展中 使用 @EventListener 注解来自定义监听器,监听指定的事件,比如下面的案例:

  1. @Component
  2. public class UserManagerListener {
  3. //ApplicationEvent能监听到所有的事件,如果为EmailEvent.class则只能监听到关于邮件的事件
  4. //EventListener有两个参数(可以不写,直接在方法参数里面写上要监听的事件即可):
  5. // classes:表示哪一个事件类
  6. // condition:当满足什么条件是会调用该方法
  7. @EventListener(classes = ApplicationEvent.class)
  8. public void listen(ApplicationEvent event){
  9. System.out.println("用户管理功能监听到的事件。。。。"+event);
  10. }
  11. }

  通过上面的案例发现代码比实现 ApplicationListener 接口更简洁,那这个注解为什么功能这么强大呢,接下来我们来分析它的源码:

  1. /**
  2. * @author Stephane Nicoll
  3. * @author Sam Brannen
  4. * @since 4.2
  5. * @see EventListenerMethodProcessor
  6. */
  7. @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
  8. @Retention(RetentionPolicy.RUNTIME)
  9. @Documented
  10. public @interface EventListener {
  11. .......
  12. }

  通过源码发现是通过使用 EventListenerMethodProcessor 处理器来解析该注解,将标注了 @EventListener 的方法进行解析, 获取拦截方法,对拦截方法进行转换,变成 ApplicationListener 然

后放入到 IOC 容器中,在publishEvent 时,通过 getApplicationEventMulticaster().multicastEvent(a

pplicationEvent, eventType)方法,获取到 ApplicationListener 对象,通过反射调用方法。下面是 EventListenerMethodProcessor 处理器的类图关系:

    可以看到 EventListenerMethodProcessor 是实现了 BeanFactoryPostProcessor 和 SmartInitializingSingleton 这两个接口。在前文 Spring的BeanFactoryPostProcessor探究 中讲述了

BeanFactoryPostProcessor 的执行时机,在 refresh 容器的时候, 调用 invokeBeanFactoryPostProce

ssors() 方法时, 会执行 BeanFactoryPostProcessor#postProcessBeanFactory() 方法设置一个默认的监听器工厂 :DefaultEventListenerFactory。

  1. /**
  2. * Registers {@link EventListener} methods as individual {@link ApplicationListener} instances.
  3. * Implements {@link BeanFactoryPostProcessor} (as of 5.1) primarily for early retrieval,
  4. * avoiding AOP checks for this processor bean and its {@link EventListenerFactory} delegates.
  5. *
  6. * @author Stephane Nicoll
  7. * @author Juergen Hoeller
  8. * @since 4.2
  9. * @see EventListenerFactory
  10. * @see DefaultEventListenerFactory
  11. */
  12. public class EventListenerMethodProcessor
  13. implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
  14. ......
  15. @Override
  16. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
  17. this.beanFactory = beanFactory;
  18.  
  19. Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
  20. List<EventListenerFactory> factories = new ArrayList<>(beans.values());
  21. AnnotationAwareOrderComparator.sort(factories);
  22. //DefaultEventListenerFactory
  23. this.eventListenerFactories = factories;
  24. }
  25. .......
  26. }

  而SmartInitializingSingleton 这个接口只有一个方法 afterSingletonsInstantiated(),这个方法在全部单实例创建完成之后执行,接下来对这个方法进行深入探讨,我们对 EventListenerMethodProcessor里面的实现方法 afterSingletonsInstantiated 打一个断点 debug 运行下:

    从中我们可以看到,流程是: IOC容器创建对象 --> refresh() --> finishBeanFactoryInitialization(beanFactory)(初始化剩下的所有单实例bean) --> beanFactory.preInstantiateSingletons()(初始化剩下的所有单实例bean)--> smartSingleton.afterSingletonsInstantiated()

  1. @Override
  2. public void preInstantiateSingletons() throws BeansException {
  3. if (logger.isTraceEnabled()) {
  4. logger.trace("Pre-instantiating singletons in " + this);
  5. }
  6.  
  7. // Iterate over a copy to allow for init methods which in turn register new bean definitions.
  8. // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
  9. //获取所有的注册bean名称
  10. List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
  11.  
  12. // Trigger initialization of all non-lazy singleton beans...
  13. //先创建所有的单实例bean
  14. for (String beanName : beanNames) {
  15. RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
  16. if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
  17. if (isFactoryBean(beanName)) {
  18. Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
  19. if (bean instanceof FactoryBean) {
  20. final FactoryBean<?> factory = (FactoryBean<?>) bean;
  21. boolean isEagerInit;
  22. if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
  23. isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
  24. ((SmartFactoryBean<?>) factory)::isEagerInit,
  25. getAccessControlContext());
  26. }
  27. else {
  28. isEagerInit = (factory instanceof SmartFactoryBean &&
  29. ((SmartFactoryBean<?>) factory).isEagerInit());
  30. }
  31. if (isEagerInit) {
  32. getBean(beanName);//创建bean实例
  33. }
  34. }
  35. }
  36. else {
  37. getBean(beanName);//创建bean实例
  38. }
  39. }
  40. }
  41.  
  42. // Trigger post-initialization callback for all applicable beans...
  43. //创建完成后进行遍历,如果bean是SmartInitializingSingleton类型,执行afterSingletonsInstantiated方法
  44. for (String beanName : beanNames) {
  45. Object singletonInstance = getSingleton(beanName);
  46. if (singletonInstance instanceof SmartInitializingSingleton) {
  47. final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
  48. if (System.getSecurityManager() != null) {
  49. AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
  50. smartSingleton.afterSingletonsInstantiated();
  51. return null;
  52. }, getAccessControlContext());
  53. }
  54. else {
  55. smartSingleton.afterSingletonsInstantiated();
  56. }
  57. }
  58. }
  59. }

  从上面可以看出其调用时机是,遍历容器中注册的 BeanDefinition, 调用所有 getBean() 方法创建实例之后, 才会开始遍历执行 afterSingletonsInstantiated() 方法。

  接下来详细解析下 EventListenerMethodProcessor 的 afterSingletonsInstantiated 方法,重点看 processBean 方法:

  1. @Override
  2. public void afterSingletonsInstantiated() {
  3. ConfigurableListableBeanFactory beanFactory = this.beanFactory;
  4. Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
  5. String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
  6. for (String beanName : beanNames) {
  7. if (!ScopedProxyUtils.isScopedTarget(beanName)) {
  8. Class<?> type = null;
  9. try {
  10. type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
  11. }
  12. catch (Throwable ex) {
  13. // An unresolvable bean type, probably from a lazy bean - let's ignore it.
  14. if (logger.isDebugEnabled()) {
  15. logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
  16. }
  17. }
  18. if (type != null) {
  19. if (ScopedObject.class.isAssignableFrom(type)) {
  20. try {
  21. Class<?> targetClass = AutoProxyUtils.determineTargetClass(
  22. beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));
  23. if (targetClass != null) {
  24. type = targetClass;
  25. }
  26. }
  27. catch (Throwable ex) {
  28. // An invalid scoped proxy arrangement - let's ignore it.
  29. if (logger.isDebugEnabled()) {
  30. logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);
  31. }
  32. }
  33. }
  34. try {
  35. processBean(beanName, type);
  36. }
  37. catch (Throwable ex) {
  38. throw new BeanInitializationException("Failed to process @EventListener " +
  39. "annotation on bean with name '" + beanName + "'", ex);
  40. }
  41. }
  42. }
  43. }
  44. }
  45. private void processBean(final String beanName, final Class<?> targetType) {
  46. //不包含没有注解的class,注解是EventListener的类型,是Spring容器的类型
  47. if (!this.nonAnnotatedClasses.contains(targetType) &&
  48. AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
  49. !isSpringContainerClass(targetType)) {
  50.  
  51. Map<Method, EventListener> annotatedMethods = null;
  52. try {
  53. //获取标注了 @EventListener 注解的监听方法
  54. annotatedMethods = MethodIntrospector.selectMethods(targetType,
  55. (MethodIntrospector.MetadataLookup<EventListener>) method ->
  56. AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
  57. }
  58. catch (Throwable ex) {
  59. // An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
  60. if (logger.isDebugEnabled()) {
  61. logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
  62. }
  63. }
  64. //监听方法添加到没有注解的集合
  65. if (CollectionUtils.isEmpty(annotatedMethods)) {
  66. this.nonAnnotatedClasses.add(targetType);
  67. if (logger.isTraceEnabled()) {
  68. logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
  69. }
  70. }
  71. else {
  72. // Non-empty set of methods
  73. ConfigurableApplicationContext context = this.applicationContext;
  74. Assert.state(context != null, "No ApplicationContext set");
  75. List<EventListenerFactory> factories = this.eventListenerFactories;
  76. Assert.state(factories != null, "EventListenerFactory List not initialized");
  77. for (Method method : annotatedMethods.keySet()) {
  78. for (EventListenerFactory factory : factories) {
  79. // 判断是否支持该方法 在DefaultEventListenerFactory中写死的返回true
  80. if (factory.supportsMethod(method)) {
  81. //选择方法 beanName 这里是AddDataEventListener的beanName 默认是addDataEventListener
  82. Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
  83. //将监听方法转换为ApplicationListener(ApplicationListenerMethodAdapter)对象
  84. ApplicationListener<?> applicationListener =
  85. factory.createApplicationListener(beanName, targetType, methodToUse);
  86. // 如果是ApplicationListenerMethodAdapter对象 就把context和evaluator传进去
  87. if (applicationListener instanceof ApplicationListenerMethodAdapter) {
  88. ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
  89. }
  90. //将创建的 ApplicationListener 加入到容器中
  91. context.addApplicationListener(applicationListener);
  92. break;
  93. }
  94. }
  95. }
  96. if (logger.isDebugEnabled()) {
  97. logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
  98. beanName + "': " + annotatedMethods);
  99. }
  100. }
  101. }
  102. }
  103. //class是在org.springframework包下,注解类型不是组件
  104. private static boolean isSpringContainerClass(Class<?> clazz) {
  105. return (clazz.getName().startsWith("org.springframework.") &&
  106. !AnnotatedElementUtils.isAnnotated(ClassUtils.getUserClass(clazz), Component.class));
  107. }

  后面就是添加listener到Context中:

    1)如果有applicationEventMulticaster,添加到ApplicationContext.applicationEventMulticas

ter中;

    2)如果没有applicationEventMulticaster,添加到ApplicationContext.applicationListeners中;

  最后是触发事件监听了 AbstractApplicationContext.publishEvent --> SimpleApplicationEventMulticaster.multicastEvent --> invokeListener --> doInvokeListener --> ApplicationListenerMethodAdapter.onApplicationEvent

  1. @Override
  2. public void onApplicationEvent(ApplicationEvent event) {
  3. processEvent(event);
  4. }
  5. ApplicationListenerMethodAdapter#processEvent
  6. public void processEvent(ApplicationEvent event) {
  7. Object[] args = resolveArguments(event);
  8. if (shouldHandle(event, args)) {
  9. // 反射执行真正的方法
  10. Object result = doInvoke(args);
  11. if (result != null) {
  12. handleResult(result);
  13. }
  14. else {
  15. logger.trace("No result object given - no result to handle");
  16. }
  17. }
  18. }

  在ApplicationListenerMethodAdapter.doInvoke中会反射执行真正的方法:

  1. protected Object doInvoke(Object... args) {
  2. //获取目标对象
  3. Object bean = getTargetBean();
  4. ReflectionUtils.makeAccessible(this.method);
  5. try {
  6. //反射执行监听方法
  7. return this.method.invoke(bean, args);
  8. }
  9. catch (IllegalArgumentException ex) {
  10. assertTargetBean(this.method, bean, args);
  11. throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);
  12. }
  13. catch (IllegalAccessException ex) {
  14. throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);
  15. }
  16. catch (InvocationTargetException ex) {
  17. // Throw underlying exception
  18. Throwable targetException = ex.getTargetException();
  19. if (targetException instanceof RuntimeException) {
  20. throw (RuntimeException) targetException;
  21. }
  22. else {
  23. String msg = getInvocationErrorMessage(bean, "Failed to invoke event listener method", args);
  24. throw new UndeclaredThrowableException(targetException, msg);
  25. }
  26. }
  27. }

Spring笔记(8) - @EventListener注解探究的更多相关文章

  1. Spring笔记02_注解_IOC

    目录 Spring笔记02 1. Spring整合连接池 1.1 Spring整合C3P0 1.2 Spring整合DBCP 1.3 最终版 2. 基于注解的IOC配置 2.1 导包 2.2 配置文件 ...

  2. Spring笔记(6) - Spring的BeanFactoryPostProcessor探究

    一.背景 在说BeanFactoryPostProcessor之前,先来说下BeanPostProcessor,在前文Spring笔记(2) - 生命周期/属性赋值/自动装配及部分源码解析中讲解了Be ...

  3. Spring笔记04_AOP注解开发_模板_事务

    目录 1. Spring基于AspectJ的注解的AOP开发 1. 1 SpringAOP的注解入门 1.2 Spring的AOP的注解通知类型 1.2.1 @Before:前置通知 1.2.2 @A ...

  4. Spring笔记(7) - Spring的事件和监听机制

    一.背景 事件机制作为一种编程机制,在很多开发语言中都提供了支持,同时许多开源框架的设计中都使用了事件机制,比如SpringFramework. 在 Java 语言中,Java 的事件机制参与者有3种 ...

  5. Spring笔记01_下载_概述_监听器

    目录 Spring笔记01 1.Spring介绍 1.1 Spring概述 1.2 Spring好处 1.3 Spring结构体系 1.4 在项目中的架构 1.5 程序的耦合和解耦 2. Spring ...

  6. Spring笔记:IOC基础

    Spring笔记:IOC基础 引入IOC 在Java基础中,我们往往使用常见关键字来完成服务对象的创建.举个例子我们有很多U盘,有金士顿的(KingstonUSBDisk)的.闪迪的(SanUSBDi ...

  7. Spring笔记(3) - debug源码AOP原理解析

    案例 @EnableAspectJAutoProxy//开启基于注解的aop模式 @Configuration public class AOPConfig { //业务逻辑类加入容器中 @Bean ...

  8. Spring系列20:注解详解和Spring注解增强(基础内功)

    有部分小伙伴反馈说前面基于注解的Spring中大量使用注解,由于对Java的注解不熟悉,有点难受.建议总结一篇的Java注解的基础知识,那么,它来了! 本文内容 什么是注解? 如何定义注解 如何使用注 ...

  9. [Spring框架]Spring开发实例: XML+注解.

    前言: 本文为自己学习Spring记录所用, 文章内容包括Spring的概述已经简单开发, 主要涉及IOC相关知识, 希望能够对新入门Spring的同学有帮助, 也希望大家一起讨论相关的知识. 一. ...

随机推荐

  1. 【C++设计模式二】工厂模式

    (1)定义3 简单工厂模式中,每新增一个具体产品,就需要修改工厂类内部的判断逻辑.为了不修改工厂类,遵循开闭原则,工厂方法模式中不再使用工厂类统一创建所有的具体产品,而是针对不同的产品设计了不同的工厂 ...

  2. 快速掌握ES6语法

    常量变量 let and const 先说说常量和变量的概念吧, 常量是说那种进行一次赋值后不会更改的值,比如说游戏账户的 ID, 变量是说赋值后有更改的需求的,比如游戏名,游戏密码. 在之前的 Ja ...

  3. cmake引入三方库

    目录结构 . |-- cmake | |-- CompilerSettings.cmake | |-- Options.cmake | `-- ProjectJsonCpp.cmake |-- CMa ...

  4. Jenkins+pytest+Allure搭建自动化测试

    持续集成(CONTINUOUS INTEGRATION) 在CI环境中,开发人员将会频繁地向主干提交代码.这些新提交的代码在最终合并到主干前,需要经过编译和自动化测试流进行验证. 持续交付(CONTI ...

  5. 【组合计数】visit

    题目大意 从 \((0,0)\) 开始,每次只可走上下左右一个单位长度,可走重复路,求第 \(T\) 步正好走到 \((n,m)\) 的方案数. 答案要求对 \(MOD\) 取模,\(MOD\) 保证 ...

  6. JavaSE学习笔记03流程控制

    Java流程控制 1.顺序结构 java的基本结构就是顺序结构,除非特别指明,否则就按照顺序一句一句往下执行. 顺序结构是最简单的算法结构,它是任何一个算法都离不开的一种基本算法结构. 2. 选择结构 ...

  7. HashMap的理解

    Hashmap的实现原理 默认它是存放了16个链表头的数组,存储数据的时候key先生成hashcode,根据hashcode把数据存放到相应链表中,那么是如何确定存放到哪个链表中的呢?采用hashco ...

  8. Centos7 使用nginx部署vue项目

    一.安装nginx #设置源 sudo rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0 ...

  9. 怎么提高selenium脚本的自动化执行效率?

    1.使用配置更高的电脑,选择更快的网络环境:2.使用效率更高的语言,比如 java 比 python,这种方案可行性不高:3.能直接访问网址的,就不要一步一步点击:4.不要盲目增加 sleep,尽量使 ...

  10. Java学习的第十三天

    1.object类及其方法 Java类的浅层克隆,深层克隆 2.克隆很难 3.明天学习java的继承,关键字