• 5 Spring ApplicationListener 扩展篇


    EventListener

    前面通过实现ApplicationListener,就可以创建一个监听了,但是还是相对麻烦,因为一般我们是把监听和业务处理分开,能不能直接把监听器注解到业务方法中?EventListener就实现了这种方法。

    使用范例

    业务类的方法上直接添加相关的注解即可。

    public class OrgServiceImpl {
        @EventListener
        public void add(OrgChangeEvent event){
            System.out.println("org event listener "+event.getSource().toString());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    上述通过: @EventListener,就创建了一个监听OrgChangeEvent的监听器。

    注解解析

    @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface EventListener {
    
       /**
        * Alias for {@link #classes}.
        */
       @AliasFor("classes")
       Class[] value() default {};
    
       /**
        * The event classes that this listener handles.
        * 

    If this attribute is specified with a single value, the * annotated method may optionally accept a single parameter. * However, if this attribute is specified with multiple values, * the annotated method must not declare any parameters. */ @AliasFor("value") Class[] classes() default {}; 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
    • 23
    • 24
    • 25

    可以针对多个事件进行注解,例如:@EventListener({OrgChangeEvent.class, UserChangeEvent.class})

    原理

    常见的方式,普通创建一个监听,需要实现ApplicationListener接口,那么EventListener注解又如何实现的?

    Processing of @EventListener annotations is performed via the internal EventListenerMethodProcessor bean which gets registered automatically when using Java config or manually via the  or  element when using XML config.
    
    • 1

    上述EventLIstener注解的说明,发现了EventListenerMethodProcessor来实现EventListener的执行的。

    EventListenerMethodProcessor

    EventListenerMethodProcessor实现了三个接口:SmartInitializingSingleton(Bean对象初始化完成的后置对象), ApplicationContextAware(获取ApplicationContext), BeanFactoryPostProcessor(BeanFactory的后置处理器)。按照执行顺序,ApplicationContextAware>BeanFactoryPostProcessor>SmartInitializingSignleton。其中ApplicationContextAware都熟悉,可以直接忽略。

    BeanFactroyPostProcessor

    获取eventListenerFactories对象,整个Spring默认的实现对象就一个:DefaultEventListenerFactory

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
       this.beanFactory = beanFactory;
    
       Map beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
       List factories = new ArrayList<>(beans.values());
       AnnotationAwareOrderComparator.sort(factories);
       this.eventListenerFactories = factories;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    DefaultEventListenerFactory

    EventListenerFactory主要是创建ApplicationListener,看看DefaultEventListenerFactory的源码

    public class DefaultEventListenerFactory implements EventListenerFactory, Ordered {
    
       private int order = LOWEST_PRECEDENCE;
    
    
       public void setOrder(int order) {
          this.order = order;
       }
    
       @Override
       public int getOrder() {
          return this.order;
       }
    
    
       @Override
       public boolean supportsMethod(Method method) {
          return true;
       }
    
       @Override
       public ApplicationListener createApplicationListener(String beanName, Class type, Method method) {
          //核心:创建ApplicationListener,ApplicationListenerMethodAdapter适配器
          return new ApplicationListenerMethodAdapter(beanName, type, method);
       }
    
    }
    
    • 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

    SmartInitializingSingleton

    SmartInitializingSignLeton的调用时机:AbstractApplicationContext.refresh(finishBeanFactoryInitialization->preInstantiateSingletons),初始化所有的非延迟加载的单例对象后,针对所有初始化完成的Bean,如果该Bean是SmartInitializingSingleton实现类,会单独调用afterSingletonsInstantiated方法。

    @Override
    public void afterSingletonsInstantiated() {
       ConfigurableListableBeanFactory beanFactory = this.beanFactory;
       Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
       //获取所有的Bean
       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 {
                   //核心,处理Bean
                   processBean(beanName, type);
                }
                catch (Throwable ex) {
                   throw new BeanInitializationException("Failed to process @EventListener " +
                         "annotation on bean with name '" + beanName + "'", ex);
                }
             }
          }
       }
    }
    
    • 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

    获取到符合条件的Bean对象,开始处理。

    private void processBean(final String beanName, final Class targetType) {
       //
       if (!this.nonAnnotatedClasses.contains(targetType) &&
             //判断当前类是否具有EventListener注解,无论是方法还是字段,EventListener只支持方法和注解。
             AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
             !isSpringContainerClass(targetType)) {
    
          Map annotatedMethods = null;
          try {
             //获取所有带有EventListener的方法
             annotatedMethods = MethodIntrospector.selectMethods(targetType,
                   (MethodIntrospector.MetadataLookup) 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 = this.applicationContext;
             Assert.state(context != null, "No ApplicationContext set");
             List factories = this.eventListenerFactories;
             Assert.state(factories != null, "EventListenerFactory List not initialized");
             for (Method method : annotatedMethods.keySet()) {
                for (EventListenerFactory factory : factories) {
                   //EventListenerFactory的钩子方法
                   if (factory.supportsMethod(method)) {
                      //获取方法,如果当前类没有,就获取接口的方法
                      Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
                      //根据Bean的名称和对应的Method,调用工厂,创建监听对象,其实就是适配器监听
                      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

    ApplicationListenerMethodAdapter

    EventListener最终转化为ApplicationListenerMethodAdapter,ApplicationListenerMethodAdapter的结构如下:

    在这里插入图片描述

    因此,我们只需要看看ApplicationListenerMethodAdapter的onApplicationEvent如何处理事件的。

    public void onApplicationEvent(ApplicationEvent event) {
       processEvent(event);
    }
    
    public void processEvent(ApplicationEvent event) {
       //组装方法执行时的参数
       Object[] args = resolveArguments(event);
       if (shouldHandle(event, args)) {
          //执行方法
          Object result = doInvoke(args);
          if (result != null) {
             //有意思的地方,如果返回值非null,并且是普通数据,
             //例如:基本数据格式,竟然还会包装成PayloadApplicationEvent,再次发送一次事件
             handleResult(result);
          }
          else {
             logger.trace("No result object given - no result to handle");
          }
       }
    }
    
    @Nullable
    protected Object doInvoke(Object... args) {
       Object bean = getTargetBean();
       // Detect package-protected NullBean instance through equals(null) check
       if (bean.equals(null)) {
          return null;
       }
    
       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);
          }
       }
    }
    
    • 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

    思考

    通过EventLitener的实现方式,其实后续也可以实现方法级别的注解,具体操作步骤如下:

    1. 通过SmartInitializingSignLeton的afterSingletonsInstantiated方法,获取所有Bean中带有指定注解的方法。

    2. 针对对象的特定方法生成相关的适配器对象,这样就可以正常的调用该对象的方法。

    通过持有对象+方法,生成适配器对象。

    其实相关的实践有很多,可以在SpringBoot中,搜索:SmartInitializingSignLeton的实现类,会发现很多能力都是通过上述方式实现。

  • 相关阅读:
    Elasticsearch实用教程---从门->进阶->精通
    “集世界精华·展中国风采”2024北京智能科技展会(世亚智博会)
    [C# 循环跳转]-C# 中的 while/do-while/for/foreach 循环结构以及 break/continue 跳转语句
    微信小程序如何在切换页面后原页面状态不变
    大学排行榜 : qs全球世界 大学排行榜
    egg-mongoose update更新无效解决方案
    百度文心智能体平台(想象即现实):轻松上手,开启智能新时代!创建属于自己的智能体应用。
    thinkphp5.1 获取缓存cache(‘cache_name‘)特别慢,php 7.0 unserialize 特别慢
    混迹互联网,怎么才能写出好简历?
    本地安装telepresence,访问K8S集群 Mac(m1) 非管理員
  • 原文地址:https://blog.csdn.net/u010652576/article/details/126263194