Spring Event原理分析

在复杂的业务开发的时候,对于业务的解耦有利于系统的健壮性和灵活性,Spring内部spring-context包中event包下提供了对于事件的支持。

1.简单使用

    @Resource
    ApplicationEventPublisher applicationEventPublisher;
    // 发送事件
    public void sendEvent() {
        EventDTO eventDTO = new EventDTO();
        applicationEventPublisher.publishEvent(eventDTO);
    }
    // 监听事件
    @EventListener
    public void listenEvent(EventDTO eventDTO) {
        System.out.println( Thread.currentThread().getName()+" "+eventDTO);
    }

2.流程分析

image.png

注:Multicaster为ApplicationEventMulticaster。

3.源码分析

在这整个流程中,Multicaster广播器主要负责发送事件到各个订阅的Listener方法中,整个流程的核心节点。在分析整个Event之前需要对在Spring启动时,如何注入广播器等等工作做一个简单分析。<br />Spring的启动注入流程如下:

    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

在以上的方法中,对于启动的过程,我们主要分析 initApplicationEventMulticaster 方法以及 registerListeners(); 方法还有 finishBeanFactoryInitialization(beanFactory);。方法一主要是注册事件广播器,方法二主要是注册监听器,方法三主要是在所有的非懒加载的Bean初始化后将含有@EventListener注解的Bean包装为ApplicationListener中,然后注入到Spring IOC容器中。
注册广播器的核心代码如下:

// 创建一个简单广播器,传入beanFactory主要用于后期获取BeanFactory中的Listener
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
// 将广播器单例bean注入到Spring IOC容器中
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);

注册Listener到广播器的核心代码如下:

        // Register statically specified listeners first.
        for (ApplicationListener<?> listener : getApplicationListeners()) {
            getApplicationEventMulticaster().addApplicationListener(listener);
        }

        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let post-processors apply to them!
        String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
        for (String listenerBeanName : listenerBeanNames) {
            getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }

        // Publish early application events now that we finally have a multicaster...
        // earlyApplicationEvents 是容器刚刚初始化所构建的Event链表,里面主要保存在广播器够着之前
        // 需要发放的Event
        Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if (earlyEventsToProcess != null) {
            for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
                getApplicationEventMulticaster().multicastEvent(earlyEvent);
            }
        }

此方法主要将容器中所有声明的ApplicationLister的Bean对象加载到广播器中,并且发送在广播器和Bean准备期间所需要发送的事件。
将容器中初始化好的Spring Bean中包含@EventListener注解的方法和Bean包裹到一个新通用的ApplicationLister子类(即ApplicationListenerMethodAdapter中),核心代码如下:

    private void processBean(final String beanName, final Class<?> targetType) {
        if (!this.nonAnnotatedClasses.contains(targetType) &&
                AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
                !isSpringContainerClass(targetType)) {

            Map<Method, EventListener> annotatedMethods = null;
            try {
                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) {
                        if (factory.supportsMethod(method)) {
                            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);
                }
            }
        }
    }

这里重点介绍一下ApplicationListenerMethodAdapter类,其继承自ApplicationLister实现onApplicationEvent方法,传入参数:String beanName, Class<?> targetClass, Method method(@EventListener的目标方法)。其实现如下:

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

doInvoke会利用反射的方式执行目标方法,handleResult会将目标犯法执行的结果继续当做Event发送出去。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。