【杭州研发中心-后端二团队】springboot源码解析-监听器详情

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 简介:Spring的事件驱动模型由三部分组成:事件: ApplicationEvent ,继承自JDK的 EventObject ,所有事件都要继承它,也就是被观察者事件发布者: ApplicationEventPublisher 及 ApplicationEventMulticaster 接口,使用这个接口,就可以发布事件了事件监听者: ApplicationListener ,继承JDK的 EventListener ,所有监听者都继承它,也就是我们所说的观察者,当然我们也可以使用注解 @EventListener ,效果是一样的

springboot源码解析-监听器详情

简介:Spring的事件驱动模型由三部分组成:
事件: ApplicationEvent ,继承自JDK的 EventObject ,所有事件都要继承它,也就是被观察者
事件发布者: ApplicationEventPublisher 及 ApplicationEventMulticaster 接口,使用这个接口,就可以发布事件了
事件监听者: ApplicationListener ,继承JDK的 EventListener ,所有监听者都继承它,也就是我们所说的观察者,当然我们也可以使用注解 @EventListener ,效果是一样的

​ 在看springboot的源码过程中,发现内部使用了大量的监听器,下面来看下监听器的作用。

在springboot的监听器有如下两类:

# Run Listeners
#事件发布运行监听器,是springboot中配置的唯一一个应用运行监听器,作用是通过一个多路广播器,将springboot运行状态的变化,构建成事件,并广播给各个监听器
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener(),\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

​ 当程序开始运行的时候,可以看到启动了一个运行时监听器,并且创建了一个SpringApplicationRunListeners对象,该对象是一个封装工具类,封装了所有的启动监听器:代码如下

class SpringApplicationRunListeners {

    private final Log log;

    //启动类监听器
    private final List<SpringApplicationRunListener> listeners;

    SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
        this.log = log;
        this.listeners = new ArrayList<>(listeners);
    }
//启动上下文事件监听
    void starting() {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.starting();
        }
    }
//environment准备完毕事件监听
    void environmentPrepared(ConfigurableEnvironment environment) {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.environmentPrepared(environment);
        }
    }
//spring上下文准备完毕事件监听
    void contextPrepared(ConfigurableApplicationContext context) {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.contextPrepared(context);
        }
    }
//上下文配置类加载事件监听
    void contextLoaded(ConfigurableApplicationContext context) {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.contextLoaded(context);
        }
    }
//上下文刷新调用事件
    void started(ConfigurableApplicationContext context) {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.started(context);
        }
    }
//上下文刷新完成,在run方法执行完之前调用该事件
    void running(ConfigurableApplicationContext context) {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.running(context);
        }
    }
//在运行过程中失败调起的事件
    void failed(ConfigurableApplicationContext context, Throwable exception) {
        for (SpringApplicationRunListener listener : this.listeners) {
            callFailedListener(listener, context, exception);
        }
    }

    private void callFailedListener(SpringApplicationRunListener listener, ConfigurableApplicationContext context,
            Throwable exception) {
        try {
            listener.failed(context, exception);
        }
        catch (Throwable ex) {
            if (exception == null) {
                ReflectionUtils.rethrowRuntimeException(ex);
            }
            if (this.log.isDebugEnabled()) {
                this.log.error("Error handling failed", ex);
            }
            else {
                String message = ex.getMessage();
                message = (message != null) ? message : "no error message";
                this.log.warn("Error handling failed (" + message + ")");
            }
        }
    }

}

​ 在启动源码的流程中,我们知道不同的方法会在不同的时间点触发执行,然后广播出不同的事件,进入到EventPublishingRunListener类中

public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
        this.initialMulticaster = new SimpleApplicationEventMulticaster();
        for (ApplicationListener<?> listener : application.getListeners()) {
            this.initialMulticaster.addApplicationListener(listener);
        }
    }

​ 在当前类的构造方法中默认创建了SimpleApplicationEventMulticaster类,用来完成创建全局的事件发布功能

@Override
    public void starting() {
        this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
    }

    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
        this.initialMulticaster
                .multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
    }

    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        this.initialMulticaster
                .multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
    }

    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        for (ApplicationListener<?> listener : this.application.getListeners()) {
            if (listener instanceof ApplicationContextAware) {
                ((ApplicationContextAware) listener).setApplicationContext(context);
            }
            context.addApplicationListener(listener);
        }
        this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
    }

    @Override
    public void started(ConfigurableApplicationContext context) {
        context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
    }

    @Override
    public void running(ConfigurableApplicationContext context) {
        context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
    }

    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception);
        if (context != null && context.isActive()) {
            // Listeners have been registered to the application context so we should
            // use it at this point if we can
            context.publishEvent(event);
        }
        else {
            // An inactive context may not have a multicaster so we use our multicaster to
            // call all of the context's listeners instead
            if (context instanceof AbstractApplicationContext) {
                for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
                        .getApplicationListeners()) {
                    this.initialMulticaster.addApplicationListener(listener);
                }
            }
            this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
            this.initialMulticaster.multicastEvent(event);
        }
    }

​ 在进行事件广播的时候,会进入如下方法:

@Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        //获取线程池
        Executor executor = getTaskExecutor();
        //根据事件类型选取需要通知的监听器
        for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            //如果不为空,则异步执行    
            if (executor != null) {
                executor.execute(() -> invokeListener(listener, event));
            }
            else {
                //如果为空,则同步执行
                invokeListener(listener, event);
            }
        }
    }

​ 在进行事件广播之前,需要将监听器进行过滤,符合类型的留下,不符合类型的过滤掉

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

        Object source = event.getSource();
        Class<?> sourceType = (source != null ? source.getClass() : null);
        ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);

        // Quick check for existing entry on ConcurrentHashMap...
        ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
        if (retriever != null) {
            return retriever.getApplicationListeners();
        }

        if (this.beanClassLoader == null ||
                (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
                        (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
            // Fully synchronized building and caching of a ListenerRetriever
            synchronized (this.retrievalMutex) {
                retriever = this.retrieverCache.get(cacheKey);
                if (retriever != null) {
                    return retriever.getApplicationListeners();
                }
                retriever = new ListenerRetriever(true);
                Collection<ApplicationListener<?>> listeners =
                        retrieveApplicationListeners(eventType, sourceType, retriever);
                this.retrieverCache.put(cacheKey, retriever);
                return listeners;
            }
        }
        else {
            // No ListenerRetriever caching -> no synchronization necessary
            return retrieveApplicationListeners(eventType, sourceType, null);
        }
    }

​ 实际处理判断逻辑的类:

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

        List<ApplicationListener<?>> allListeners = new ArrayList<>();
        Set<ApplicationListener<?>> listeners;
        Set<String> listenerBeans;
        synchronized (this.retrievalMutex) {
            listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
            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) {
                    retriever.applicationListeners.add(listener);
                }
                allListeners.add(listener);
            }
        }

        // Add listeners by bean name, potentially overlapping with programmatically
        // registered listeners above - but here potentially with additional metadata.
        if (!listenerBeans.isEmpty()) {
            ConfigurableBeanFactory beanFactory = getBeanFactory();
            for (String listenerBeanName : listenerBeans) {
                try {
                    if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
                        ApplicationListener<?> listener =
                                beanFactory.getBean(listenerBeanName, ApplicationListener.class);
                        if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
                            if (retriever != null) {
                                if (beanFactory.isSingleton(listenerBeanName)) {
                                    retriever.applicationListeners.add(listener);
                                }
                                else {
                                    retriever.applicationListenerBeans.add(listenerBeanName);
                                }
                            }
                            allListeners.add(listener);
                        }
                    }
                    else {
                        // Remove non-matching listeners that originally came from
                        // ApplicationListenerDetector, possibly ruled out by additional
                        // BeanDefinition metadata (e.g. factory method generics) above.
                        Object listener = beanFactory.getSingleton(listenerBeanName);
                        if (retriever != null) {
                            retriever.applicationListeners.remove(listener);
                        }
                        allListeners.remove(listener);
                    }
                }
                catch (NoSuchBeanDefinitionException ex) {
                    // Singleton listener instance (without backing bean definition) disappeared -
                    // probably in the middle of the destruction phase
                }
            }
        }

        AnnotationAwareOrderComparator.sort(allListeners);
        if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
            retriever.applicationListeners.clear();
            retriever.applicationListeners.addAll(allListeners);
        }
        return allListeners;
    }

在监听器实例化之前,检查是否符合固定的类型

        protected boolean supportsEvent(
            ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
        //判断监听器是否是GenericApplicationListener子类,如不是返回一个GenericApplicationListenerAdapter
        GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
                (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
        return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
    }
public interface GenericApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
    boolean supportsEventType(ResolvableType eventType);
    default boolean supportsSourceType(@Nullable Class<?> sourceType) {
        return true;
    }
    @Override
    default int getOrder() {
        return LOWEST_PRECEDENCE;
    }

}

此时可以看到GenericApplicationListener类,该类是spring提供的用于重写匹配监听器事件的接口,如果需要判断的监听器是GenericApplicationListener的子类,说明类型匹配方法已被重现,就调用子类的匹配方法,如果不是,提供一个默认的适配器来匹配GenericApplicationListenerAdapter

    public boolean supportsEventType(ResolvableType eventType) {
        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));
        }
    }

可以看到该类最终调用的是declaredEventType.isAssignableFrom(eventType)方法,也就是说,如果我们没有重写监听器匹配方法,那么发布的事件 event 会被监听 event以及监听event的父类的监听器监听到。

相关文章
|
2月前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
2天前
|
数据可视化 项目管理
个人和团队都好用的年度复盘工具:看板与KPT方法解析
本文带你了解高效方法KPT复盘法(Keep、Problem、Try),结合看板工具,帮助你理清头绪,快速完成年度复盘。
29 7
个人和团队都好用的年度复盘工具:看板与KPT方法解析
|
9天前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
20天前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
101 13
|
28天前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
2月前
|
前端开发 Java Maven
深入解析:如何用 Spring Boot 实现分页和排序
深入解析:如何用 Spring Boot 实现分页和排序
59 2
|
2月前
|
敏捷开发 数据可视化 项目管理
看板办团队协作工具能提高团队效率吗?深度解析
在快节奏的工作环境中,高效的团队协作与任务管理成为企业提升效率的关键。看板作为一种流行的工具,通过可视化管理任务进度,促进团队协作,提高透明度,帮助团队成员实时了解项目状态,确保任务不遗漏,支持远程办公与跨团队合作。
54 0
看板办团队协作工具能提高团队效率吗?深度解析
|
29天前
|
安全 Java API
实现跨域请求:Spring Boot后端的解决方案
本文介绍了在Spring Boot中处理跨域请求的三种方法:使用`@CrossOrigin`注解、全局配置以及自定义过滤器。每种方法都适用于不同的场景和需求,帮助开发者灵活地解决跨域问题,确保前后端交互顺畅与安全。
|
2月前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
86 2

热门文章

最新文章

推荐镜像

更多