当前位置: 首页 > article >正文

Spring源码分析之事件机制——观察者模式(二)

目录

获取监听器的入口方法

实际检索监听器的核心方法

监听器类型检查方法 

监听器的注册过程

监听器的存储结构

过程总结


Spring源码分析之事件机制——观察者模式(一)-CSDN博客

Spring源码分析之事件机制——观察者模式(二)-CSDN博客

Spring源码分析之事件机制——观察者模式(三)-CSDN博客

这两篇文章是这个篇章的前篇和后篇,感兴趣的读者可以阅读一下,从spring源码分析观察者模式

获取监听器的入口方法

public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster {
    // 存储所有监听器的集合
    private final DefaultListenerRetrieverdefaultRetriever = new DefaultListenerRetriever();

    // 缓存事件类型与监听器的映射关系
    private final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = 
        new ConcurrentHashMap<>(64);

   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);
    
    // 准备新的缓存检索器
    CachedListenerRetriever newRetriever = null;
    // 尝试从缓存中获取已存在的检索器
    CachedListenerRetriever existingRetriever = 
        (CachedListenerRetriever)this.retrieverCache.get(cacheKey);
    
    // 如果缓存中不存在,且类加载器安全(防止类加载器泄漏),则创建新的检索器
    if (existingRetriever == null && 
        (this.beanClassLoader == null || 
         ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && 
         (sourceType == null || 
          ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
        
        newRetriever = new CachedListenerRetriever();
        // 使用CAS操作将新检索器放入缓存
        existingRetriever = (CachedListenerRetriever)this.retrieverCache
            .putIfAbsent(cacheKey, newRetriever);
        if (existingRetriever != null) {
            newRetriever = null;
        }
    }

    // 如果存在缓存的检索器,尝试获取缓存的监听器
    if (existingRetriever != null) {
        Collection<ApplicationListener<?>> result = 
            existingRetriever.getApplicationListeners();
        if (result != null) {
            return result;
        }
    }

    // 如果缓存未命中,检索匹配的监听器
    return retrieveApplicationListeners(eventType, sourceType, newRetriever);
}

这个方法实现了监听器检索的缓存机制,通过缓存来提高性能,同时考虑了类加载器安全性。 

实际检索监听器的核心方法

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;
    
    // 同步获取已注册的监听器和监听器Bean名称
    Set<ApplicationListener<?>> listeners;
    Set<String> listenerBeans;
    synchronized(this.defaultRetriever) {
        listeners = new LinkedHashSet(this.defaultRetriever.applicationListeners);
        listenerBeans = new LinkedHashSet(this.defaultRetriever.applicationListenerBeans);
    }

    // 处理已实例化的监听器
    for(ApplicationListener<?> listener : listeners) {
        if (supportsEvent(listener, eventType, sourceType)) {
            if (retriever != null) {
                filteredListeners.add(listener);
            }
            allListeners.add(listener);
        }
    }

    // 处理监听器Bean
    if (!listenerBeans.isEmpty()) {
        ConfigurableBeanFactory beanFactory = getBeanFactory();
        for(String listenerBeanName : listenerBeans) {
            try {
                // 检查Bean是否支持该事件
                if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
                    ApplicationListener<?> listener = beanFactory.getBean(
                        listenerBeanName, ApplicationListener.class);
                    // 避免重复添加
                    if (!allListeners.contains(listener) && 
                        supportsEvent(listener, eventType, sourceType)) {
                        // 根据Bean的作用域决定是否缓存
                        if (retriever != null) {
                            if (beanFactory.isSingleton(listenerBeanName)) {
                                filteredListeners.add(listener);
                            } else {
                                filteredListenerBeans.add(listenerBeanName);
                            }
                        }
                        allListeners.add(listener);
                    }
                } else {
                    // 移除不支持的监听器
                    Object listener = beanFactory.getSingleton(listenerBeanName);
                    if (retriever != null) {
                        filteredListeners.remove(listener);
                    }
                    allListeners.remove(listener);
                }
            } catch (NoSuchBeanDefinitionException ex) {
                // 忽略不存在的Bean
            }
        }
    }

    // 按照@Order注解排序
    AnnotationAwareOrderComparator.sort(allListeners);
    
    // 更新缓存
    if (retriever != null) {
        if (filteredListenerBeans.isEmpty()) {
            retriever.applicationListeners = new LinkedHashSet(allListeners);
            retriever.applicationListenerBeans = filteredListenerBeans;
        } else {
            retriever.applicationListeners = filteredListeners;
            retriever.applicationListenerBeans = filteredListenerBeans;
        }
    }

    return allListeners;
}

这个方法是实际检索监听器的核心实现,它处理了已实例化的监听器和尚未实例化的监听器Bean,同时考虑了Bean的作用域和缓存策略。

监听器类型检查方法 

private boolean supportsEvent(
        ConfigurableBeanFactory beanFactory, 
        String listenerBeanName, 
        ResolvableType eventType) {
        
    // 获取监听器的类型
    Class<?> listenerType = beanFactory.getType(listenerBeanName);
    
    // 如果是特殊的监听器类型,直接返回true
    if (listenerType != null && 
        !GenericApplicationListener.class.isAssignableFrom(listenerType) && 
        !SmartApplicationListener.class.isAssignableFrom(listenerType)) {
        
        // 检查是否支持事件类型
        if (!supportsEvent(listenerType, eventType)) {
            return false;
        }
        
        try {
            // 获取Bean定义并检查泛型类型
            BeanDefinition bd = beanFactory.getMergedBeanDefinition(listenerBeanName);
            ResolvableType genericEventType = bd.getResolvableType()
                .as(ApplicationListener.class)
                .getGeneric(new int[0]);
            return genericEventType == ResolvableType.NONE || 
                   genericEventType.isAssignableFrom(eventType);
        } catch (NoSuchBeanDefinitionException ex) {
            return true;
        }
    }
    return true;
}

这个方法负责检查监听器是否支持特定的事件类型,它考虑了泛型类型和特殊的监听器接口。整个实现展示了Spring如何高效地管理和匹配事件监听器,通过缓存机制提高性能,同时保证类型安全和正确的监听器顺序。这种实现既保证了功能的完整性,又确保了运行时的效率。 

监听器的注册过程

public abstract class AbstractApplicationContext {
    
    // 在容器刷新过程中注册监听器
    protected void registerListeners() {
        // 首先注册静态指定的监听器
        for (ApplicationListener<?> listener : getApplicationListeners()) {
            getApplicationEventMulticaster().addApplicationListener(listener);
        }

        // 获取配置的监听器Bean名称
        String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
        for (String listenerBeanName : listenerBeanNames) {
            // 将监听器Bean名称添加到多播器
            getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }

        // 发布早期事件
        Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
            for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
                getApplicationEventMulticaster().multicastEvent(earlyEvent);
            }
        }
    }
}

这段代码展示了Spring如何在容器启动时注册监听器。对于像UserCacheListener这样的组件,它们会被Spring容器扫描并注册到ApplicationEventMulticaster中。

监听器的存储结构

 private class CachedListenerRetriever {
        @Nullable
        public volatile Set<ApplicationListener<?>> applicationListeners;
        @Nullable
        public volatile Set<String> applicationListenerBeans;

        private CachedListenerRetriever() {
        }

        @Nullable
        public Collection<ApplicationListener<?>> getApplicationListeners() {
            Set<ApplicationListener<?>> applicationListeners = this.applicationListeners;
            Set<String> applicationListenerBeans = this.applicationListenerBeans;
            if (applicationListeners != null && applicationListenerBeans != null) {
                List<ApplicationListener<?>> allListeners = new ArrayList(applicationListeners.size() + applicationListenerBeans.size());
                allListeners.addAll(applicationListeners);
                if (!applicationListenerBeans.isEmpty()) {
                    BeanFactory beanFactory = AbstractApplicationEventMulticaster.this.getBeanFactory();

                    for(String listenerBeanName : applicationListenerBeans) {
                        try {
                            allListeners.add(beanFactory.getBean(listenerBeanName, ApplicationListener.class));
                        } catch (NoSuchBeanDefinitionException var8) {
                        }
                    }
                }

                if (!applicationListenerBeans.isEmpty()) {
                    AnnotationAwareOrderComparator.sort(allListeners);
                }

                return allListeners;
            } else {
                return null;
            }
        }
    }

CachedListenerRetriever 其实是AbstractApplicationEventMulticaster 的静态内部类

过程总结

Spring扫描到@Component注解,创建BeanDefinition

Spring容器启动时实例化Bean

在AbstractApplicationContext.registerListeners()中注册


http://www.kler.cn/a/467724.html

相关文章:

  • Neo4j的部署和操作
  • macOS 安装 python3.11
  • linux-centos-安装miniconda3
  • linux定时执行脚本的方法
  • 一文讲明白朴素贝叶斯算法及其计算公式(入门普及)
  • 蓝桥杯备赛:C++基础,顺序表和vector(STL)
  • 理解linux内核中的几种地址
  • Java枚举和常量类的区别以及优缺点
  • wordpress开发之实现使用第三方库qrcode-generator生成二维码并上传和展示
  • 若依使用 Undertow 替代 Tomcat 容器
  • 密码学原理技术-第十一章-Hash Functions
  • java_配置使用nacos完整示例
  • 默认ip无法访问,利用dhcp功能获取ip进行访问的方法
  • 三子棋游戏
  • centos双网卡不能上网
  • Nginx:安装部署和升级(平滑升级)
  • js-19-手写题
  • 软件逆向之标志位
  • 【测试工具】 Postman 基本使用
  • 【Linux】调度优先级(谦让度)
  • spring、spring boot、Springmvc 的区别和关系
  • k8s集群部署 - Dashboard v2.7
  • MySQL 8 主从同步配置(Master-Slave Replication)
  • ESP32移植Openharmony外设篇(7)土壤湿度传感器YL-69
  • Python进阶-08-继承性
  • 编译 C++ 程序:分离与保留调试信息以支持 GDB 对 Core 文件的调试