Spring筆記(8) - @EventListener註解探究

碼猿手發表於2020-11-15

  在上文中講了Spring的事件監聽機制,流程是:定義事件、監聽器,釋出事件,控制檯輸出監聽到的事件內容。

  在上文的擴充套件中 使用 @EventListener 註解來自定義監聽器,監聽指定的事件,比如下面的案例:

@Component
public class UserManagerListener {
    //ApplicationEvent能監聽到所有的事件,如果為EmailEvent.class則只能監聽到關於郵件的事件
    //EventListener有兩個引數(可以不寫,直接在方法引數裡面寫上要監聽的事件即可):
    //    classes:表示哪一個事件類
    //    condition:當滿足什麼條件是會呼叫該方法
    @EventListener(classes = ApplicationEvent.class)
    public void listen(ApplicationEvent event){
        System.out.println("使用者管理功能監聽到的事件。。。。"+event);
    }
}

  通過上面的案例發現程式碼比實現 ApplicationListener 介面更簡潔,那這個註解為什麼功能這麼強大呢,接下來我們來分析它的原始碼:

/**
 * @author Stephane Nicoll
 * @author Sam Brannen
 * @since 4.2
 * @see EventListenerMethodProcessor
 */
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EventListener {
.......
}

  通過原始碼發現是通過使用 EventListenerMethodProcessor 處理器來解析該註解,將標註了 @EventListener 的方法進行解析, 獲取攔截方法,對攔截方法進行轉換,變成 ApplicationListener 然

後放入到 IOC 容器中,在publishEvent 時,通過 getApplicationEventMulticaster().multicastEvent(a

pplicationEvent, eventType)方法,獲取到 ApplicationListener 物件,通過反射呼叫方法。下面是 EventListenerMethodProcessor 處理器的類圖關係:

    可以看到 EventListenerMethodProcessor 是實現了 BeanFactoryPostProcessor 和 SmartInitializingSingleton 這兩個介面。在前文 Spring的BeanFactoryPostProcessor探究 中講述了

 BeanFactoryPostProcessor 的執行時機,在 refresh 容器的時候, 呼叫 invokeBeanFactoryPostProce

ssors() 方法時, 會執行 BeanFactoryPostProcessor#postProcessBeanFactory() 方法設定一個預設的監聽器工廠 :DefaultEventListenerFactory。

/**
 * Registers {@link EventListener} methods as individual {@link ApplicationListener} instances.
 * Implements {@link BeanFactoryPostProcessor} (as of 5.1) primarily for early retrieval,
 * avoiding AOP checks for this processor bean and its {@link EventListenerFactory} delegates.
 *
 * @author Stephane Nicoll
 * @author Juergen Hoeller
 * @since 4.2
 * @see EventListenerFactory
 * @see DefaultEventListenerFactory
 */
    public class EventListenerMethodProcessor
        implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
    ......
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        this.beanFactory = beanFactory;

        Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
        List<EventListenerFactory> factories = new ArrayList<>(beans.values());
        AnnotationAwareOrderComparator.sort(factories);
        //DefaultEventListenerFactory
        this.eventListenerFactories = factories;
    }
    .......
}

  而SmartInitializingSingleton 這個介面只有一個方法 afterSingletonsInstantiated(),這個方法在全部單例項建立完成之後執行,接下來對這個方法進行深入探討,我們對 EventListenerMethodProcessor裡面的實現方法 afterSingletonsInstantiated 打一個斷點 debug 執行下:

    從中我們可以看到,流程是: IOC容器建立物件 --> refresh() --> finishBeanFactoryInitialization(beanFactory)(初始化剩下的所有單例項bean) --> beanFactory.preInstantiateSingletons()(初始化剩下的所有單例項bean)--> smartSingleton.afterSingletonsInstantiated()

    @Override
    public void preInstantiateSingletons() throws BeansException {
        if (logger.isTraceEnabled()) {
            logger.trace("Pre-instantiating singletons in " + this);
        }

        // Iterate over a copy to allow for init methods which in turn register new bean definitions.
        // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
        //獲取所有的註冊bean名稱
        List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

        // Trigger initialization of all non-lazy singleton beans...
        //先建立所有的單例項bean
        for (String beanName : beanNames) {
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                if (isFactoryBean(beanName)) {
                    Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                    if (bean instanceof FactoryBean) {
                        final FactoryBean<?> factory = (FactoryBean<?>) bean;
                        boolean isEagerInit;
                        if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                            isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                                            ((SmartFactoryBean<?>) factory)::isEagerInit,
                                    getAccessControlContext());
                        }
                        else {
                            isEagerInit = (factory instanceof SmartFactoryBean &&
                                    ((SmartFactoryBean<?>) factory).isEagerInit());
                        }
                        if (isEagerInit) {
                            getBean(beanName);//建立bean例項
                        }
                    }
                }
                else {
                    getBean(beanName);//建立bean例項
                }
            }
        }

        // Trigger post-initialization callback for all applicable beans...
        //建立完成後進行遍歷,如果bean是SmartInitializingSingleton型別,執行afterSingletonsInstantiated方法
        for (String beanName : beanNames) {
            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 {
                    smartSingleton.afterSingletonsInstantiated();
                }
            }
        }
    }

  從上面可以看出其呼叫時機是,遍歷容器中註冊的 BeanDefinition, 呼叫所有 getBean() 方法建立例項之後, 才會開始遍歷執行 afterSingletonsInstantiated() 方法。

  接下來詳細解析下 EventListenerMethodProcessor 的 afterSingletonsInstantiated 方法,重點看 processBean 方法:

    @Override
    public void afterSingletonsInstantiated() {
        ConfigurableListableBeanFactory beanFactory = this.beanFactory;
        Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
        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 {
                        processBean(beanName, type);
                    }
                    catch (Throwable ex) {
                        throw new BeanInitializationException("Failed to process @EventListener " +
                                "annotation on bean with name '" + beanName + "'", ex);
                    }
                }
            }
        }
    }
    private void processBean(final String beanName, final Class<?> targetType) {
        //不包含沒有註解的class,註解是EventListener的型別,是Spring容器的型別
        if (!this.nonAnnotatedClasses.contains(targetType) &&
                AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
                !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)) {
                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<EventListenerFactory> factories = this.eventListenerFactories;
                Assert.state(factories != null, "EventListenerFactory List not initialized");
                for (Method method : annotatedMethods.keySet()) {
                    for (EventListenerFactory factory : factories) {
                        // 判斷是否支援該方法  在DefaultEventListenerFactory中寫死的返回true
                        if (factory.supportsMethod(method)) {
                            //選擇方法  beanName 這裡是AddDataEventListener的beanName 預設是addDataEventListener
                            Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
                            //將監聽方法轉換為ApplicationListener(ApplicationListenerMethodAdapter)物件
                            ApplicationListener<?> applicationListener =
                                    factory.createApplicationListener(beanName, targetType, methodToUse);
                            // 如果是ApplicationListenerMethodAdapter物件 就把context和evaluator傳進去
                            if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                                ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
                            }
                            //將建立的 ApplicationListener 加入到容器中
                            context.addApplicationListener(applicationListener);
                            break;
                        }
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
                            beanName + "': " + annotatedMethods);
                }
            }
        }
    }
    //class是在org.springframework包下,註解型別不是元件
    private static boolean isSpringContainerClass(Class<?> clazz) {
        return (clazz.getName().startsWith("org.springframework.") &&
                !AnnotatedElementUtils.isAnnotated(ClassUtils.getUserClass(clazz), Component.class));
    }

   後面就是新增listener到Context中:

    1)如果有applicationEventMulticaster,新增到ApplicationContext.applicationEventMulticas

ter中;

    2)如果沒有applicationEventMulticaster,新增到ApplicationContext.applicationListeners中;

  最後是觸發事件監聽了 AbstractApplicationContext.publishEvent --> SimpleApplicationEventMulticaster.multicastEvent --> invokeListener --> doInvokeListener --> ApplicationListenerMethodAdapter.onApplicationEvent

@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中會反射執行真正的方法:

 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);
      }
   }
}

相關文章