Spring-Context注解源码之@EventListener

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

[[410307]]

 注解说明

Annotation that marks a method as a listener for application events.

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

属性说明

public @interface EventListener { 
 
   /** 
    * 同class 
    */ 
   @AliasFor("classes"
   Class<?>[] value() default {}; 
 
   /** 
    * 监听事件的类型 
    * 如果这个属性长度不为空,则以这个属性的为准 
    * 如果这个属性长度为空,则以被标注方法的参数为准 
    */ 
   @AliasFor("value"
   Class<?>[] classes() default {}; 
 
   /** 
    * 以spring表达的方式计算事件监听是否需要触发 
    */ 
   String condition() default ""
 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.

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

使用示例

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

  • 1.
  • 2.
  • 3.
  • 4.

相关源码

EventListenerMethodProcessor

/** 
 * 检测bean里面是否包含 @EventListener 
 */ 
private void processBean(final String beanName, final Class<?> targetType) { 
   if (!this.nonAnnotatedClasses.contains(targetType) && 
         !targetType.getName().startsWith("java") && 
         !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)) { 
         // 如果这个类一个包含 @EventListener 方法都没有则缓存到 nonAnnotatedClasses 中,减少重复计算 
         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 = this.applicationContext; 
         Assert.state(context != null"No ApplicationContext set"); 
         // 可以创建自定义 EventListenerFactory,如果不创建,默认拥有 DefaultEventListenerFactory 
         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)) { 
                  // 根据方法创建 applicationListener,并将 applicationListener 添加给容器 
                  Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName)); 
                  ApplicationListener<?> applicationListener = 
                        factory.createApplicationListener(beanName, targetType, methodToUse); 
                  if (applicationListener instanceof ApplicationListenerMethodAdapter) { 
                     ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator); 
                  } 
                  context.addApplicationListener(applicationListener); 
                  break; 
               } 
            } 
         } 
         if (logger.isDebugEnabled()) { 
            logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" + 
                  beanName + "': " + annotatedMethods); 
         } 
      } 
   } 

  • 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.

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

ApplicationListenerMethodAdapter

/** 
 * 解析时间监听器支持的事件类型 
 */ 
private static List<ResolvableType> resolveDeclaredEventTypes(Method method, @Nullable EventListener ann) { 
   int count = method.getParameterCount(); 
   if (count > 1) { 
      // 如果方法本身参数超过1个,则直接抛出异常 
      throw new IllegalStateException( 
            "Maximum one parameter is allowed for event listener method: " + method); 
   } 
 
   if (ann != null) { 
      // 取出 注解中的 classes属性 
      Class<?>[] classes = ann.classes(); 
      if (classes.length > 0) { 
         // 如果classes属性不为空,则解析classes属性并返回作为事件解析类型 
         List<ResolvableType> types = new ArrayList<>(classes.length); 
         for (Class<?> eventType : classes) { 
            types.add(ResolvableType.forClass(eventType)); 
         } 
         return types; 
      } 
   } 
 
   // 如果传入的classes属性为空,并且方法没有参数,也抛出异常 
   if (count == 0) { 
      throw new IllegalStateException( 
            "Event parameter is mandatory for event listener method: " + method); 
   } 
   return Collections.singletonList(ResolvableType.forMethodParameter(method, 0)); 

  • 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.

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

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

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

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

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

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

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

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

责任编辑:武晓燕 来源: 今日头条
相关推荐

2023-04-10 11:00:00

注解Demo源码

2023-07-10 08:43:53

SpringIDEA

2022-02-19 07:41:36

Bean注解项目

2022-02-20 07:28:13

Spring注解用法

2022-12-07 08:02:43

Spring流程IOC

2022-06-09 07:27:14

JavaSpring容器

2022-05-30 11:17:44

Spring容器配置

2019-09-09 06:30:06

Springboot程序员开发

2020-12-20 10:02:17

ContextReactrender

2023-05-08 08:11:49

@Component使用场景时序图

2020-10-14 06:23:54

SpringBean实例化

2009-06-15 17:48:32

Spring注解注入属性

2011-04-15 09:44:45

Spring

2023-06-02 16:24:46

SpringBootSSM

2021-08-27 07:38:21

AndroidDialogContext

2017-08-02 14:44:06

Spring Boot开发注解

2021-03-08 00:11:02

Spring注解开发

2015-03-31 18:26:43

陌陌社交

2021-03-11 11:14:39

鸿蒙HarmonyOS应用

2022-06-07 07:58:45

SpringSpring AOP
点赞
收藏

51CTO技术栈公众号