• SpringEvent 事件发布/监听机制相关源码解析


    前言


    该篇文章是我学习SpringEvent源码实现的过程,看源码的过程中,会涉及到程序启动时系统监听类的注入、自定义监听类的注入、事件发布后如何通知监听类等等,如果一一记录,就显得又长又混乱了,所以本篇只涉及事件发布后如何通知监听类的源码,其他的只会稍微提一提。

    SpringEvent的介绍和应用


    关于SpringEvent的介绍和应用可以看我之前写的文章

    SpringEvent介绍与应用

    环境配置


    • JDK8
    • Spring boot 2.6.10

    ApplicationEventPublisher 的publishEvent方法


    我们使用SpringEvent的时候,是使用ApplicationEventPublisherpublishEvent方法进行发布事件的操作,看一下publishEvent方法做了什么操作

    PS: ApplicationEventPublisher是一个接口,而接口ApplicationContext实现了该接口,Springboot默认实现是AbstractApplicationContext,所以我们看的实际类是AbstractApplicationContext的publishEvent方法

    protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
        Assert.notNull(event, "Event must not be null");
        Object applicationEvent;
        
        //检查传过来的event是否是了ApplicationEvent的实例
        if (event instanceof ApplicationEvent) {
            applicationEvent = (ApplicationEvent)event;
        } else {
           //如果不是,则会使用ApplicationEvent的实例包裹住event类
            applicationEvent = new PayloadApplicationEvent(this, event);
            if (eventType == null) {
                eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
            }
        }
        
        //earlyApplicationEvents 该事件是早期应用的事件模式,现在用的是多播的方式,也就是else部分的代码
        if (this.earlyApplicationEvents != null) {
            this.earlyApplicationEvents.add(applicationEvent);
        } else {
            //获取默认实现的事件多播器,并调用多播的方法,SpringEvent的发布会走此方法
           this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType);
        }
    
        if (this.parent != null) {
            if (this.parent instanceof AbstractApplicationContext) {
                ((AbstractApplicationContext)this.parent).publishEvent(event, eventType);
            } else {
                this.parent.publishEvent(event);
            }
        }
    
    }
    
    • 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

    上述的代码在我理解中,作用是用来检验发布的事件是否符合要求,并解析事件的类型,方便后续获取具体的监听类中
    接下来我们需要关注的是

    this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType);
    
    • 1

    this.getApplicationEventMulticaster() 获取实现了ApplicationEventMulticaster的实例,SpringBoot默认实现是SimpleApplicationEventMulticaster

    SimpleApplicationEventMulticaster的multicastEvent方法


    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
       
       //如果eventType是空,则重新获取event的类型
        ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
        
        //获取任务线程池,如果没有自定义赋值,那么executor默认都会为null。
        Executor executor = this.getTaskExecutor();
        
        //this.getApplicationListeners(event, type)是获取event的监听类,获取监听类后进行遍历
        Iterator var5 = this.getApplicationListeners(event, type).iterator();
    
        while(var5.hasNext()) {
            //获取event的监听类
            ApplicationListener listener = (ApplicationListener)var5.next();
            
            //检测executor是否为null,如果不为null,则使用executor的线程异步跑监听类
            if (executor != null) {
                executor.execute(() -> {
                    this.invokeListener(listener, event);
                });
            } else {
                this.invokeListener(listener, event);
            }
        }
    
    }
    
    • 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

    该方法主要是获取事件对应的全部监听类,并进行调用
    下面我们看是如何获取到事件的监听类。

    SimpleApplicationEventMulticaster的getApplicationListeners方法


    protected Collection> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
        Object source = event.getSource();
        Class sourceType = source != null ? source.getClass() : null;
        
        //下面三行代码是为了从缓存中获取对应的监听类
        AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType);
        AbstractApplicationEventMulticaster.CachedListenerRetriever newRetriever = null;
        AbstractApplicationEventMulticaster.CachedListenerRetriever existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.get(cacheKey);
        
        //如果缓存不存在,则对newRetriever和existingRetriever进行初步处理
        if (existingRetriever == null && 
            (this.beanClassLoader == null || 
            ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
            (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) 
           {
       
            newRetriever = new AbstractApplicationEventMulticaster.CachedListenerRetriever();
            
            111 = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
            
            if (existingRetriever != null) {
                newRetriever = null;
            }
        }
    
       //如果缓存存在对应的监听类,则返回。
        if (existingRetriever != null) {
            Collection> result = existingRetriever.getApplicationListeners();
            if (result != null) {
                return result;
            }
        }
    
       //获取对应的监听类(当缓存获取不到监听类就会走这一步)
        return this.retrieveApplicationListeners(eventType, sourceType, newRetriever);
    }
    
    • 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

    该方法的主要目的是为了先从缓存获取监听类,如果获取不到对应的监听类,再进行实时获取

    SimpleApplicationEventMulticaster的retrieveApplicationListeners方法


    该方法比较长,这里分成几个部分进行说明

    • 准备部分 获取全部的监听类
    • 第一部分 系统自带的监听类集合listeners的处理
    • 第二部分 包含着自定义的监听类集合listenerBeans的处理,我们写的自定义监听类就在这个集合
    • 第三部分 将找到的监听类进行排序

    说明:retrieveApplicationListeners方法的第三个参数retriever是用来做缓存listener用的

    准备部分

    private Collection> retrieveApplicationListeners(ResolvableType eventType, 
    @Nullable Class sourceType,
    @Nullable AbstractApplicationEventMulticaster.CachedListenerRetriever retriever) 
    {
       //用来作为结果返回的集合
        List> allListeners = new ArrayList();
        
        //filteredListeners和filteredListenerBeans的作用是用来做缓存数据的
        //所以这里会识别retriever是否为null,如果不为null则新创集合
        Set> filteredListeners = retriever != null ? new LinkedHashSet() : null;
        Set filteredListenerBeans = retriever != null ? new LinkedHashSet() : null;
        
        //存储监控类
        LinkedHashSet listeners;
        //存储String类型的Bean名称
        LinkedHashSet listenerBeans;
        
        synchronized(this.defaultRetriever) {
            //将全部监控类放入listeners
            listeners = new LinkedHashSet(this.defaultRetriever.applicationListeners);
            //将自定义的监控类放入listenerBeans(我们自己定义的监听类就在里面)
            listenerBeans = new LinkedHashSet(this.defaultRetriever.applicationListenerBeans);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    this.defaultRetriever.applicationListeners

    this.defaultRetriever.applicationListenerBeans
    在这里插入图片描述

    第一部分


    private Collection> retrieveApplicationListeners(ResolvableType eventType, 
    @Nullable Class sourceType,
    @Nullable AbstractApplicationEventMulticaster.CachedListenerRetriever retriever) 
    {
       //准备部分
       
       
       //第一部分
        Iterator var9 = listeners.iterator();
    
        while(var9.hasNext()) {
        
            //取出listeners中的元素
            ApplicationListener listener = (ApplicationListener)var9.next();
            
            //this.supportsEvent是用来筛选的,判断是不是符合事件的监听类
            if (this.supportsEvent(listener, eventType, sourceType)) {
            
                //如果缓存参数retriever存在,则往缓存集合存入数据
                if (retriever != null) {
                    filteredListeners.add(listener);
                }
                
                //加入到结果集中
                allListeners.add(listener);
            }
        }
    
    
    }
    
    • 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

    第一部分的作用在于筛选对应的监控类,并把这些监控类也放进缓存集合中

    第二部分


    private Collection> retrieveApplicationListeners(ResolvableType eventType, 
    @Nullable Class sourceType,
    @Nullable AbstractApplicationEventMulticaster.CachedListenerRetriever retriever) 
    {
       //准备部分
       
       
       //第一部分
       
       
       //第二部分
        if (!listenerBeans.isEmpty()) {
            ConfigurableBeanFactory beanFactory = this.getBeanFactory();
            Iterator var16 = listenerBeans.iterator();
    
            while(var16.hasNext()) {
                //获取bean名称
                String listenerBeanName = (String)var16.next();
    
               try {
                
                    //筛选是否是事件对应的监听类
                    if (this.supportsEvent(beanFactory, listenerBeanName, eventType)) {
                    
                       //根据beanFactory取到bean
                        ApplicationListener listener = (ApplicationListener)beanFactory.getBean(listenerBeanName, ApplicationListener.class);
                        
                        //如果结果集合allListeners中不存在该监听类并且是事件对应的监听类
                        //则往结果集和缓存集合中插入
                        if (!allListeners.contains(listener) && this.supportsEvent(listener, eventType, sourceType)) {
                        
                            //判断缓存是否存在
                            if (retriever != null) {
                                if (beanFactory.isSingleton(listenerBeanName)) {
                                    filteredListeners.add(listener);
                                } else {
                                    filteredListenerBeans.add(listenerBeanName);
                                }
                            }
    
                            //往结果集中加入
                            allListeners.add(listener);
                        }
                    } 
                    //这里进入else代码表示,集合元素并不是事件对应的监听器
                    else {
                        Object listener = beanFactory.getSingleton(listenerBeanName);
                        //对缓存进行处理
                        if (retriever != null) {
                            filteredListeners.remove(listener);
                        }
                        //
                        allListeners.remove(listener);
                    }
                   } catch (NoSuchBeanDefinitionException var13) {
                     
                    
                   }
            }
        }
    
    }
    
    • 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
    • 59
    • 60
    • 61
    • 62

    第二部分大致分两个做法。

    • 是先根据bean名称判断是不是事件对应的监听类,如果是,则获取对应的bean类,不是,则从结果集和缓存集合中删除。
    • 在上一个条件是的情况下,再检查该bean是否不存在于结果集但又是事件对应的监听类,如果是,则进行插入。

    这部分虽说我知道是做什么的,但是我不知道为什么要这么做,如果有知道的大佬,希望能通过评论区告诉我下

    第三部分


    private Collection> retrieveApplicationListeners(ResolvableType eventType, 
    @Nullable Class sourceType,
    @Nullable AbstractApplicationEventMulticaster.CachedListenerRetriever retriever) 
    {
       //准备部分
       
       
       //第一部分
       
       
       //第二部分
       
       //第三部分
       //对结果集监听类进行排序
       AnnotationAwareOrderComparator.sort(allListeners);
       
       //如果缓存retriever不为空,则进行处理
       if (retriever != null) {
           //如果filteredListenerBeans集合不为空,
           if (filteredListenerBeans.isEmpty()) {
               retriever.applicationListeners = new LinkedHashSet(allListeners);
               retriever.applicationListenerBeans = filteredListenerBeans;
           }
           else {
           
               retriever.applicationListeners = filteredListeners;
               retriever.applicationListenerBeans = filteredListenerBeans;
           }
       }
    
    
    }
    
    • 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

    第三个部分比较简单,即对监听类进行排序和缓存的一些处理

    总结


    SpringEvent的源码已大致描述完毕,谢谢看官愿意看到这里(源码的文章个人觉得很难描述的一下就明白了),如果有什么误人子弟的内容存在,可以在评论区回复。

  • 相关阅读:
    苹果,设计思维的“布道者”
    Vue+nodejs服装库存管理系统-vscode前后端分离
    python音频转文字调用baidu
    npm run dev后浏览器没有出现页面
    c 文本终端直接写framebuffer 显示直线
    java计算机毕业设计网络教育学习平台源程序+mysql+系统+lw文档+远程调试
    zookeeper节点的状态和权限控制
    Makefile(make)之(3)输出变量值
    oracle锁表
    webgl计算包围盒大小
  • 原文地址:https://blog.csdn.net/MDZZ666/article/details/126236866