文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Spring-Context注解源码之@EventListener

2024-12-03 02:33

关注

以注解的方式将一个方法标记为事件监听器。如果对于spring事件监听机制还不了解的小伙伴点击查看一文彻底搞懂spring事件监听机制

属性说明

  1. public @interface EventListener { 
  2.  
  3.     
  4.    @AliasFor("classes"
  5.    Class[] value() default {}; 
  6.  
  7.     
  8.    @AliasFor("value"
  9.    Class[] classes() default {}; 
  10.  
  11.     
  12.    String condition() default ""
  13.  

通过上述属性,我们可以发现,相比起实现接口的方式创建事件监听器,用注解的方式灵活性更加大,不仅可以指定多个接受事件类型,还可以增加是否触发的条件。

使用示例

  1. @EventListener 
  2. public void customListener1(MyEvent event) { 
  3.     System.out.println("接受事件customListener1"); 

相关源码

EventListenerMethodProcessor

  1.  
  2. private void processBean(final String beanName, final Class targetType) { 
  3.    if (!this.nonAnnotatedClasses.contains(targetType) && 
  4.          !targetType.getName().startsWith("java") && 
  5.          !isSpringContainerClass(targetType)) { 
  6.  
  7.       Map annotatedMethods = null
  8.       try { 
  9.          // 找到所有包含 @EventListener 的方法 
  10.          annotatedMethods = MethodIntrospector.selectMethods(targetType, 
  11.                (MethodIntrospector.MetadataLookup) method -> 
  12.                      AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class)); 
  13.       } 
  14.       catch (Throwable ex) { 
  15.          // An unresolvable type in a method signature, probably from a lazy bean - let's ignore it. 
  16.          if (logger.isDebugEnabled()) { 
  17.             logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex); 
  18.          } 
  19.       } 
  20.  
  21.       if (CollectionUtils.isEmpty(annotatedMethods)) { 
  22.          // 如果这个类一个包含 @EventListener 方法都没有则缓存到 nonAnnotatedClasses 中,减少重复计算 
  23.          this.nonAnnotatedClasses.add(targetType); 
  24.          if (logger.isTraceEnabled()) { 
  25.             logger.trace("No @EventListener annotations found on bean class: " + targetType.getName()); 
  26.          } 
  27.       } 
  28.       else { 
  29.          // Non-empty set of methods 
  30.          ConfigurableApplicationContext context = this.applicationContext; 
  31.          Assert.state(context != null"No ApplicationContext set"); 
  32.          // 可以创建自定义 EventListenerFactory,如果不创建,默认拥有 DefaultEventListenerFactory 
  33.          List factories = this.eventListenerFactories; 
  34.          Assert.state(factories != null"EventListenerFactory List not initialized"); 
  35.          for (Method method : annotatedMethods.keySet()) { 
  36.             for (EventListenerFactory factory : factories) { 
  37.                // 对于每一个方法遍历所有的工厂,找到一个支持的工厂就进入创建并完成遍历 
  38.                if (factory.supportsMethod(method)) { 
  39.                   // 根据方法创建 applicationListener,并将 applicationListener 添加给容器 
  40.                   Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName)); 
  41.                   ApplicationListener applicationListener = 
  42.                         factory.createApplicationListener(beanName, targetType, methodToUse); 
  43.                   if (applicationListener instanceof ApplicationListenerMethodAdapter) { 
  44.                      ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator); 
  45.                   } 
  46.                   context.addApplicationListener(applicationListener); 
  47.                   break; 
  48.                } 
  49.             } 
  50.          } 
  51.          if (logger.isDebugEnabled()) { 
  52.             logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" + 
  53.                   beanName + "': " + annotatedMethods); 
  54.          } 
  55.       } 
  56.    } 

EventListenerMethodProcessor的processBean方法中,会遍历已经注册的所有的bean,找到包含有被 @EventListener 标注的方法。这些方法会被遍历已经创建的 EventListenerFactory 找到合适的工厂来生成 applicationListener,并将 applicationListener 注册到容器的事件监听器列表。

ApplicationListenerMethodAdapter

  1.  
  2. private static List resolveDeclaredEventTypes(Method method, @Nullable EventListener ann) { 
  3.    int count = method.getParameterCount(); 
  4.    if (count > 1) { 
  5.       // 如果方法本身参数超过1个,则直接抛出异常 
  6.       throw new IllegalStateException( 
  7.             "Maximum one parameter is allowed for event listener method: " + method); 
  8.    } 
  9.  
  10.    if (ann != null) { 
  11.       // 取出 注解中的 classes属性 
  12.       Class[] classes = ann.classes(); 
  13.       if (classes.length > 0) { 
  14.          // 如果classes属性不为空,则解析classes属性并返回作为事件解析类型 
  15.          List types = new ArrayList<>(classes.length); 
  16.          for (Class eventType : classes) { 
  17.             types.add(ResolvableType.forClass(eventType)); 
  18.          } 
  19.          return types; 
  20.       } 
  21.    } 
  22.  
  23.    // 如果传入的classes属性为空,并且方法没有参数,也抛出异常 
  24.    if (count == 0) { 
  25.       throw new IllegalStateException( 
  26.             "Event parameter is mandatory for event listener method: " + method); 
  27.    } 
  28.    return Collections.singletonList(ResolvableType.forMethodParameter(method, 0)); 

ApplicationListenerMethodAdapter的resolveDeclaredEventTypes方法会解析@EventListener标签的classes属性,然后根据这个属性决定事件监听器的监听的事件类型。

如果方法参数个数超过1个,直接抛出异常。这是一个事件触发以后,如果接受的方法参数个数大于1个,spring没办法给方法进行传参。

如果classes属性为空,并且方法参数个数为0个,也抛出异常。这是因为spring无法推断这个监听器需要支持什么类型的事件。

除去上面两种情况,解析都是成功,同时classes属性会优先被选择为监听的事件类型。

  1. private boolean shouldHandle(ApplicationEvent event, @Nullable Object[] args) { 
  2.    if (args == null) { 
  3.       return false
  4.    } 
  5.    String condition = getCondition(); 
  6.    if (StringUtils.hasText(condition)) { 
  7.      // 如果 condition 属性不为空,则进行spring表达式计算结果并返回 
  8.       Assert.notNull(this.evaluator, "EventExpressionEvaluator must not be null"); 
  9.       return this.evaluator.condition( 
  10.             condition, event, this.targetMethod, this.methodKey, args, this.applicationContext); 
  11.    } 
  12.    return true

ApplicationListenerMethodAdapter的shouldHandle方法会根据@EventListener标签的condition属性判断是否需要推送消息。

如果condition不为空,则使用spring表达式计算condition得到结果,结果为true的时候才推送事件。如果condition为空,则不判断直接推送。

来源:今日头条内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯