阅读 77

Spring 监听器listener原理-spring监听器源码分析(三)

  1. Spring 监听器listener原理-基本使用(一)
  2. Spring 监听器listener原理-手写监听器(二)
  3. Spring 监听器listener原理-spring监听器源码分析(三)

概述

要理解ApplicationListener的实现原理,需要对Spring的扩展点BeanPostProcessor有一点了解。这个接口是Spring最重要的接口之一,这个接口与Spring Bean的生命周期息息相关,我们常说的实例化前,实例化后,属性注入,初始化前,初始化后等等,其实都是调用了BeanPostProcessor或它子类的方法。有关于BeanPostProcessor的简单介绍可以参考文章,spring也是借助于bean的后置处理器查找实现了ApplicationListener的监听器

前面两篇文章中,我们可以总结事件发布大概有如下组件

  1. 事件广播器,可以理解是我们的applicationContext
  2. 事件ApplicationEvent
  3. 事件监听器ApplicationListener

那么Spring是如何找到所有的ApplicationListener以及是如何判断是否是当前监听器感兴趣的事件的,下面将为大家解答。

事件发布者

当Spring容器启动的时候会调用refresh初始化容器

org.springframework.context.support.AbstractApplicationContext#refresh

在refresh会调用initApplicationEventMulticaster进行事件广播器的初始化

@Override
    public void refresh() throws BeansException, IllegalStateException {
          .........省略
           // Initialize event multicaster for this context.
        initApplicationEventMulticaster();
          .........省略
}

下面代码的逻辑最要是判断容器中是否有名字叫applicationEventMulticaster的事件广播器,如果有则使用已有的(这也算是Spring的一个扩展点,也就是或如果我们创建了个名字是applicationEventMulticaster的事件广播器,那么就会使用我们自定义的),如果没有则新建默认的事件广播器SimpleApplicationEventMulticaster。这里会赋值给applicationEventMulticaster成员变量。applicationContext也实现了ApplicationEventPublisher接口,所以它拥有事件相关的所有方法,但applicationContext只是一个代理,当我们调用applicationContext.publishEvent方法时,其实调用的就是applicationEventMulticaster 这个成员变量对象。

public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//首先看spring容器中是不是已经有名字为applicationEventMulticaster的对象,
//如果有这使用容器中已有的对象并赋值给applicationEventMulticaster 
        if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
            this.applicationEventMulticaster =
                    beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
            if (logger.isTraceEnabled()) {
                logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
            }
        }
        else {
//如果没有则新建一个SimpleApplicationEventMulticaster对象,并赋值给applicationEventMulticaster ;
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
            if (logger.isTraceEnabled()) {
                logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
                        "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
            }
        }
    }

事件发布

事件发布的关键方法流程如下

org.springframework.context.support.AbstractApplicationContext#publishEvent
  -->org.springframework.context.support.AbstractApplicationContext#publishEvent
      -->org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent  //发布事件
        -->org.springframework.context.event.AbstractApplicationEventMulticaster#getApplicationListeners //找到感兴趣的事件
          -->org.springframework.context.event.AbstractApplicationEventMulticaster#retrieveApplicationListeners//找到感兴趣的事件
            -->org.springframework.context.event.AbstractApplicationEventMulticaster#supportsEvent //判断是否是感兴趣的事件

multicastEvent

multicastEvent 方法很简单,调用getApplicationListeners方法找到所有对当前事件感兴趣的监听器,如果存在线程池,则异步执行监听逻辑,否则同步执行。默认情况下执行事件的逻辑是跟发布事件是同一个线程

@Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        Executor executor = getTaskExecutor();
              //getApplicationListeners 方法找到所有的对当前事件感兴趣的监听器
        for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            if (executor != null) {
                    //如果有配置线程池,则使用线程池执行监听
                executor.execute(() -> invokeListener(listener, event));
            }
            else {
                invokeListener(listener, event);
            }
        }
    }

getApplicationListeners

getApplicationListeners方法,主要是判断缓存中有没有已经缓存好的事件,有则直接返回,没有则调用方法retrieveApplicationListeners检索监听器。

protected Collection<ApplicationListener<?>> getApplicationListeners(
            ApplicationEvent event, ResolvableType eventType) {

        Object source = event.getSource();
        Class<?> sourceType = (source != null ? source.getClass() : null);
               //生成一个缓存key
        ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);

        // Potential new retriever to populate
        CachedListenerRetriever newRetriever = null;

        // Quick check for existing entry on ConcurrentHashMap
              //判断缓存中是不是已经缓存了对该事件感兴趣的监听器
        CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);
               //没有的话,新建个键值对,并放到map中
        if (existingRetriever == null) {
            // Caching a new ListenerRetriever if possible
            if (this.beanClassLoader == null ||
                    (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
                            (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
                newRetriever = new CachedListenerRetriever();
                existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
                if (existingRetriever != null) {
                    newRetriever = null;  // no need to populate it in retrieveApplicationListeners
                }
            }
        }
            //缓存中有,直接返回
        if (existingRetriever != null) {
            Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();
            if (result != null) {
                return result;
            }
            // If result is null, the existing retriever is not fully populated yet by another thread.
            // Proceed like caching wasn't possible for this current local attempt.
        }
               //缓存中没有调用retrieveApplicationListeners方法查找事件ApplicationEvent。
        return retrieveApplicationListeners(eventType, sourceType, newRetriever);
    }

retrieveApplicationListeners

this.defaultRetriever.applicationListenersthis.defaultRetriever.applicationListenerBeans存放了所有的Spring事件,最终会调用supportsEvent方法过滤出对当期事件感兴趣的监听器

private Collection<ApplicationListener<?>> retrieveApplicationListeners(
            ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable CachedListenerRetriever retriever) {

        List<ApplicationListener<?>> allListeners = new ArrayList<>();
        Set<ApplicationListener<?>> filteredListeners = (retriever != null ? new LinkedHashSet<>() : null);
        Set<String> filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null);

        Set<ApplicationListener<?>> listeners;
        Set<String> listenerBeans;
        synchronized (this.defaultRetriever) {
                //defaultRetriever.applicationListeners存放了所有的applicationListeners
            listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
              //this.defaultRetriever.applicationListenerBeans存放的是PayloadApplicationEvent事件
            listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
        }

        // Add programmatically registered listeners, including ones coming
        // from ApplicationListenerDetector (singleton beans and inner beans).
        for (ApplicationListener<?> listener : listeners) {
             //判断是否对当期事件感兴趣
            if (supportsEvent(listener, eventType, sourceType)) {
                if (retriever != null) {
                    filteredListeners.add(listener);
                }
                allListeners.add(listener);
            }
        }
...............省略
}

这里以this.defaultRetriever.applicationListeners为例来讲解this.defaultRetriever.applicationListeners中的监听器是哪里来的。defaultRetriever.applicationListeners包含的监听器包含两种类:

  1. 实现了ApplicationListener接口。
  2. @EventListener 注解

查找实现了ApplicationListener接口的监听器。

这里关键调用ApplicationListenerDetectorpostProcessAfterInitialization方法(这个方法也就是常说的bean初始化后)和postProcessMergedBeanDefinition方法。这两个都是BeanPostProcessor的子类提供的方法。

postProcessMergedBeanDefinition方法的作用很简单,就是判断这个java类是否实现了ApplicationListener接口,是的话就是一个监听器

@Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        if (ApplicationListener.class.isAssignableFrom(beanType)) {
            this.singletonNames.put(beanName, beanDefinition.isSingleton());
        }
    }

postProcessAfterInitialization方法也很简单从singletonNames拿到所有的单例ApplicationListener
并调用this.applicationContext.addApplicationListener((ApplicationListener<?>) bean)方法,前面提到过applicationContext也实现ApplicationEventPublisher接口,拥有事件发布的所有方法,但实际执行的是赋值给成员变量applicationEventMulticaster的对象。

@Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        if (bean instanceof ApplicationListener) {
            // potentially not detected as a listener by getBeanNamesForType retrieval
            Boolean flag = this.singletonNames.get(beanName);
            if (Boolean.TRUE.equals(flag)) {
                // 拿到所有的单例ApplicationListener并添加到defaultRetriever.applicationListeners
                this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
            }
            else if (Boolean.FALSE.equals(flag)) {
                if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
                    // inner bean with other scope - can't reliably process events
                    logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
                            "but is not reachable for event multicasting by its containing ApplicationContext " +
                            "because it does not have singleton scope. Only top-level listener beans are allowed " +
                            "to be of non-singleton scope.");
                }
                this.singletonNames.remove(beanName);
            }
        }
        return bean;
    }

this.applicationContext.addApplicationListener((ApplicationListener<?>) bean)最终执行的方法如下所示。
最终调用this.defaultRetriever.applicationListeners.add(listener)方法

    public void addApplicationListener(ApplicationListener<?> listener) {
        synchronized (this.defaultRetriever) {
            // Explicitly remove target for a proxy, if registered already,
            // in order to avoid double invocations of the same listener.
            Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
            if (singletonTarget instanceof ApplicationListener) {
                this.defaultRetriever.applicationListeners.remove(singletonTarget);
            }
            this.defaultRetriever.applicationListeners.add(listener);
            this.retrieverCache.clear();
        }
    }

查找加了@EventListener 注解的监听器

查找 加了@EventListener 注解的监听器主要是通过EventListenerMethodProcessor类,由方法名可以看到,这也是一个bean的后置处理器,但是查找@EventListener注解的监听器并不是调用bean的后置处理器方法实现的,而是调用SmartInitializingSingletonafterSingletonsInstantiated方法,这个方法会在容器初始化完成之后执行。

查找的方式也很简单粗暴,直接调用beanFactory.getBeanNamesForType(Object.class)方法获取Spring容器中的所有对象

@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) {
................省略
        try {
                        processBean(beanName, type);
                    }
                    catch (Throwable ex) {
                        throw new BeanInitializationException("Failed to process @EventListener " +
                                "annotation on bean with name '" + beanName + "'", ex);
                    }
                }
            }
        }
    }

然后调用processBean方法,遍历对象中的方法是否有加了EventListener注解的方法。有则调用DefaultEventListenerFactorycreateApplicationListener方法创建一个是配置器对象ApplicationListenerMethodAdapter,构造器参数是方法对象,bean类对象,bean对象。最后调用context.addApplicationListener方法把监听器放到this.defaultRetriever.applicationListeners

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 {
           //遍历对象中的方法是否有加了EventListener注解的方法
                annotatedMethods = MethodIntrospector.selectMethods(targetType,
                        (MethodIntrospector.MetadataLookup<EventListener>) method ->
                                AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
            }
  ..............省略..................
                // 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));
        //调用DefaultEventListenerFactory的 createApplicationListener的方法创建一个适配器类
                            ApplicationListener<?> applicationListener =
                                    factory.createApplicationListener(beanName, targetType, methodToUse);
                            if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                                ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
                            }
                                  //把监听器添加到this.defaultRetriever.applicationListeners中
                            context.addApplicationListener(applicationListener);
                            break;
                        }
                    }
                
            
            }
        }
    }

查找感兴趣的事件

梳理完监听器的查找过程,最后我们来看看Spring是如何查找感兴趣的事件的。
判断对当前事件的逻辑代码还是比较清晰的,判断当前监听器是不是继承了GenericApplicationListener。如果不是继承GenericApplicationListener的监听器,将会被GenericApplicationListenerAdapter适配器再次包装。GenericApplicationListener 实现SmartApplicationListenerSmartApplicationListener实现了ApplicationListener接口。但是GenericApplicationListener 的作用是实现了两个SmartApplicationListener方法。

    protected boolean supportsEvent(
            ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {

        GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
                (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
        return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
    }

从接口方法可以看到GenericApplicationListener 的子类如果没事重写supportsEventType方法,就表示对所有的事件感兴趣,通过supportsEventType方法,我们可以自定义我们感兴趣的事件。

public interface GenericApplicationListener extends SmartApplicationListener {

    @Override
    default boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
        return supportsEventType(ResolvableType.forClass(eventType));
    }

    boolean supportsEventType(ResolvableType eventType);

}

而相对于GenericApplicationListener接口,适配类GenericApplicationListenerAdapter实现了supportsEventType方法,他的默认处理是当期监听器的泛型是不是当期事件或者是当前事件的子类(this.declaredEventType.isAssignableFrom(eventType))。

public boolean supportsEventType(ResolvableType eventType) {
        if (this.delegate instanceof GenericApplicationListener) {
            return ((GenericApplicationListener) this.delegate).supportsEventType(eventType);
        }
        else if (this.delegate instanceof SmartApplicationListener) {
            Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.resolve();
            return (eventClass != null && ((SmartApplicationListener) this.delegate).supportsEventType(eventClass));
        }
        else {
            return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
        }
    }

至此,关于Spring监听器的实现原理已经分析完毕。

文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐