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监听器的实现原理已经分析完毕。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容