5.【SpringBoot源码】SpringBoot监听机制分析

目录

一、简介

二、SpringBoot事件监听机制

1)、加载ApplicationListener监听器实现类

2)、获取运行监听器EventPublishingRunListener

3)、发布事件

4)、Spring事件发布multicastEvent() 


本篇源码基于spring-boot-2.1.0.RELEASE版本进行分析,各个版本可能存在一些差别。

一、简介

在SpringBoot启动过程中,每个不同的启动阶段会分别广播不同的内置生命周期事件,然后对应的监听器监听到事件之后会做相应的处理。比如ConfigFileApplicationListener会监听onApplicationEnvironmentPreparedEvent事件来加载配置文件application.properties的环境变量等。

springboot的监听器机制,类似我们设计模式的观察者模式,监听器机制拥有很好的扩展性。当一个事件发布后,会有不同的监听器来处理,如果我们想监听某个事件发生时做一些其它处理,那我们只需要添加一个监听器去监听这个事件即可。

SpringBoot的抽象事件对象是SpringApplicationEvent,继承自Spring的抽象事件对象ApplicationEvent,类图如下:

接下来我们分析下SpringBoot的事件监听机制的源码。

二、SpringBoot事件监听机制

通过前面对springboot启动流程的分析,我们知道,在springboot应用启动过程的整个生命周期过程中,发布了很多事件,下面我们就以这个来分析springboot的事件是如何发布的。

@SpringBootApplication
public class SampleTomcatApplication {

	public static void main(String[] args) {
		SpringApplication.run(SampleTomcatApplication.class, args);
	}

}

1)、加载ApplicationListener监听器实现类

在执行run()方法运行SpringApplication之前,首先得先创建一个SpringApplication对象,我们查看其构造方法:

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    // 传递的resourceLoader为null
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    // 记录主方法的配置类名称
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    // 推导出当前启动的项目的类型
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 加载配置在spring.factories文件中的ApplicationContextInitializer对应的类型并实例化. 并将加载的数据存储在了 initializers 成员变量中。
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 初始化监听器,并将加载的监听器实例对象存储在了listeners成员变量中
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    // 反推出main方法所在的Class对象
    this.mainApplicationClass = deduceMainApplicationClass();
}

 我们看到,在SpringApplication的构造方法中,通过setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class))初始化一些监听器,getSpringFactoriesInstances()这个方法相信大家都比较熟悉了,就是从项目中所有的"META-INF/spring.factories"文件中找到ApplicationListener对应的监听器,获取成功后,将这些监听器赋值给SpringApplication#listeners属性保存起来。

例如spring-boot/META-INF/spring.factories中配置了9个ApplicationListener,如下图:

在springboot应用启动时,它会从所有的spring.factories配置文件中加载ApplicationListener,如下图:

经过这一步之后,已经将获取到的所有ApplicationListener保存到SpringApplication对象的listeners属性中,后续使用的时候,我们就可以直接从SpringApplication对象中拿出来。

2)、获取运行监听器EventPublishingRunListener

我们看一下运行SpringApplication的run()方法:

// 运行 Spring 应用程序,创建并刷新一个新的ApplicationContext
public ConfigurableApplicationContext run(String... args) {
    // 创建一个任务执行观察器,用于统计run启动过程花了多少时间
    StopWatch stopWatch = new StopWatch();
    // 记录开始时间
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    // exceptionReporters集合用来存储异常报告器,用来报告SpringBoot启动过程的异常
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    // 设置了一个名为java.awt.headless的系统属性, 其实是想设置该应用程序,即使没有检测到显示器,也允许其启动. 对于服务器来说,是不需要显示器的,所以要这样设置.
    configureHeadlessProperty();
    // 从spring.factories配置文件中加载到EventPublishingRunListener对象并赋值给SpringApplicationRunListeners
    // EventPublishingRunListener对象主要用来发布SpringBoot启动过程中内置的一些生命周期事件,标志每个不同启动阶段
    SpringApplicationRunListeners listeners = getRunListeners(args);
    // 发布启动事件
    listeners.starting();
    try {
        // 创建ApplicationArguments对象,封装了args参数
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        // 准备环境,包括系统变量、环境变量、命令行参数、默认变量等
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        // 配置需要忽略的BeanInfo信息
        configureIgnoreBeanInfo(environment);
        // 启动时控制台打印Banner
        Banner printedBanner = printBanner(environment);
        // 根据不同类型创建不同类型的spring容器ApplicationContext应用程序上下文
        context = createApplicationContext();
        // 加载spring.factories配置文件配置的异常报告器
        exceptionReporters = getSpringFactoriesInstances(
                SpringBootExceptionReporter.class,
                new Class[] { ConfigurableApplicationContext.class }, context);
        // 准备上下文,刷新容器前的一些操作
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        // 刷新应用上下文。完成Spring IOC容器的初始化
        refreshContext(context);
        // 在刷新上下文后调用的钩子,这个方法是一个模板方法
        afterRefresh(context, applicationArguments);
        // 停止记录执行时间
        stopWatch.stop();
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass)
                    .logStarted(getApplicationLog(), stopWatch);
        }
        // 事件广播,启动完成了
        listeners.started(context);
        // 执行ApplicationRunner、CommandLineRunner的run方法,实现spring容器启动成功后需要执行的一些逻辑
        callRunners(context, applicationArguments);
    } catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }

    try {
        listeners.running(context);
    } catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    return context;
}

可以看到,springboot在启动过程中,通过getRunListeners(args)方法获取到一个spring运行监听器对象,它其实就是用于发布SpringBoot启动过程中的各种生命周期事件。 

SpringApplicationRunListeners listeners = getRunListeners(args);

private SpringApplicationRunListeners getRunListeners(String[] args) {
    Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
    // 获取spring.factories配置文件中配置的SpringApplicationRunListener,并通过反射实例化
    return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
            SpringApplicationRunListener.class, types, this, args));
}

又一次看到getSpringFactoriesInstances(),同样的,从项目中所有的"META-INF/spring.factories"文件中找到SpringApplicationRunListener对应的运行监听器,然后通过反射调用构造方法实例化。

可以看到,此时只获取到一个运行监听器---EventPublishingRunListener。因为要实例化,所以我们查看EventPublishingRunListener的构造方法:

public EventPublishingRunListener(SpringApplication application, String[] args) {
    this.application = application;
    this.args = args;
    // 初始化事件发布器
    this.initialMulticaster = new SimpleApplicationEventMulticaster();
    // 循环添加事件监听者
    // application.getListeners(): 在实例化SpringApplication时设值的: SpringApplication.SpringApplication(org.springframework.core.io.ResourceLoader, java.lang.Class<?>...)
    for (ApplicationListener<?> listener : application.getListeners()) {
        this.initialMulticaster.addApplicationListener(listener);
    }
}

在EventPublishingRunListener构造方法中,创建了一个SimpleApplicationEventMulticaster事件发布器,并赋值给成员属性initialMulticaster,它正是承担了广播SpringBoot启动时生命周期事件的职责。

除了创建SimpleApplicationEventMulticaster事件发布器之外,构造函数中还将前面在实例化SpringApplication时设值的ApplicationListener拿出来,挨个添加到事件发布器SimpleApplicationEventMulticaster中。

这一步就相当于观察者模式中的注册监听者。

3)、发布事件

在运行SpringApplication时,即run()方法中,我们可以看到在SpringBoot的启动过程中总共会发射7种不同类型的生命周期事件,来标志SpringBoot的不同启动阶段:

  • ApplicationStartingEvent:在SpringBoot启动时但在环境变量或者IOC容器创建前触发;
  • ApplicationEnvironmentPreparedEvent:SpringBoot已经开始启动,环境变量Environment已经准备好时触发;
  • ApplicationContextInitializedEvent:初始化器的初始化方法已经被调用,在bean定义加载前触发;
  • ApplicationPreparedEvent:在spring容器刷新refresh前触发;
  • ApplicationStartedEvent:在spring容器刷新后触发,在调用ApplicationRunner和CommandLineRunner的run()方法前触发,标志spring容器已经刷新,此时所有的bean实例都已经加载完成;
  • ApplicationFailedEvent:SpringBoot启动过程中遇到异常时发布的事件;
  • ApplicationReadyEvent:调用完ApplicationRunner和CommandLineRunner的run()方法后触发,标志SpringApplication已经 正在运行,即成功启动;

下面我们以listeners.starting();为例,看看EventPublishingRunListener发布事件的流程:

// org.springframework.boot.SpringApplicationRunListeners#starting
public void starting() {
    // EventPublishingRunListener
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.starting();
    }
}

// org.springframework.boot.context.event.EventPublishingRunListener#starting
public void starting() {
		// 通过事件发布器发布容器启动事件ApplicationStartingEvent
		this.initialMulticaster.multicastEvent(
				new ApplicationStartingEvent(this.application, this.args));
	}

实际上是通过SimpleApplicationEventMulticaster的multicastEvent()方法来发布事件的,事件类型为ApplicationStartingEvent。
SimpleApplicationEventMulticaster其实是spring-context中的类了,继续跟踪Spring的事件机制源码。

4)、Spring事件发布multicastEvent() 

// org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    // 循环所有监听了当前事件的监听器,执行监听器方法
    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        Executor executor = getTaskExecutor();
        // 允许指定线程池,也就是支持异步处理
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            // 同步方式
            invokeListener(listener, event);
        }
    }
}

getApplicationListeners(event, type):返回与给定事件类型匹配的 ApplicationListener 的集合,不匹配的ApplicationListener会提前被排除在外。【获得对当前event感兴趣的监听器列表】 

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

    // 事件来源,实际上就是SpringApplication对象,里面存放着【1)、加载ApplicationListener监听器实现类】的listeners
    Object source = event.getSource();
    // class org.springframework.boot.SpringApplication
    Class<?> sourceType = (source != null ? source.getClass() : null);
    //  缓存key
    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);
			// 循环所有的listeners,判断哪些listener满足条件
            // 只有对当前eventType感兴趣的listerer才会添加到监听器列表中
            Collection<ApplicationListener<?>> listeners =
                    retrieveApplicationListeners(eventType, sourceType, retriever);
            // 将满足条件的listener添加到缓存中
            this.retrieverCache.put(cacheKey, retriever);
            return listeners;
        }
    }
    else {
        // No ListenerRetriever caching -> no synchronization necessary
        return retrieveApplicationListeners(eventType, sourceType, null);
    }
}

我们查看retrieveApplicationListeners()方法:

// 真正获取到与传入的事件匹配的那些监听器listener
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) {
        // 这个defaultRetriever里面存放的就是上图中source的所有的listeners
        listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
        listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
    }

    // 循环前面获取到的10个listeners,挨个调用supportsEvent()方法判断每个listener是否感兴趣
    for (ApplicationListener<?> listener : listeners) {
        if (supportsEvent(listener, eventType, sourceType)) {
            // 如果感兴趣,则加入到retriever中applicationListeners集合里
            if (retriever != null) {
                retriever.applicationListeners.add(listener);
            }
            allListeners.add(listener);
        }
    }
    if (!listenerBeans.isEmpty()) {
        BeanFactory beanFactory = getBeanFactory();
        for (String listenerBeanName : listenerBeans) {
            try {
                Class<?> listenerType = beanFactory.getType(listenerBeanName);
                if (listenerType == null || supportsEvent(listenerType, 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);
                    
                }
            }
            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);
    }
    // 返回匹配的那些监听器listener
    return allListeners;
}

经过匹配,可以看到,从10个监听器中匹配出有4个监听器,是对org.springframework.boot.context.event.ApplicationStartingEvent这个事件感兴趣的,如下图:

我们再回过来看multicastEvent()方法源码:

// org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    // 循环所有监听了当前事件的监听器,执行监听器方法
    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        Executor executor = getTaskExecutor();
        // 允许指定线程池,也就是支持异步处理
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            // 同步方式
            invokeListener(listener, event);
        }
    }
}

前面获取到只有4个ApplicationListener监听了org.springframework.boot.context.event.ApplicationStartingEvent事件,所以会循环这4个监听器,依次触发它们的onApplicationEvent()回调方法。

这里我们挑选其中一个监听了ApplicationStartingEvent事件的监听器【LoggingApplicationListener】来分析:

可以看到,在onApplicationEvent()方法,通过instanceof来判断不同事件做不同的事情。

猜你喜欢

转载自blog.csdn.net/Weixiaohuai/article/details/128939174