SpringBoot源码解析(二)

监听器

EventPublishingRunListener

今天我们来讲监听器,话不多说先从SpringApplication#run方法中的getRunListeners讲起

java 复制代码
/**
 * Run the Spring application, creating and refreshing a new
 * {@link ApplicationContext}.
 * @param args the application arguments (usually passed from a Java main method)
 * @return a running {@link ApplicationContext}
 */
public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    configureHeadlessProperty();
    // 获取监听器
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();
   
    // ... 以下代码省略
}

进入getRunListeners方法

arduino 复制代码
private SpringApplicationRunListeners getRunListeners(String[] args) {
    Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
    return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
          SpringApplicationRunListener.class, types, this, args));
}

如果看过SpringFactoriesLoader的话应该就很熟悉这段代码了,这里的getSpringFactoriesInstances就是通过这个工厂加载类来加载实体类,贴上代码,具体不再详细说明,可以看我的上一篇文章,注意这个方法传入的第一个参数是SpringApplicationRunListener.class

typescript 复制代码
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
       Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    // Use names and ensure unique to protect against duplicates
    Set<String> names = new LinkedHashSet<>(
          SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
          classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

根据第一个参数,也就是说我们最后会在spring.factories中找到对应的实例也就是EventPublishingRunListener

ini 复制代码
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

先来看下EventPublishingRunListener是做什么的

从源代码中可以看到EventPublishingRunListener实现了SpringApplicationRunListener这个接口,该接口定义了几个方法用于监听SpringApplication启动和运行或者叫生命周期的不同阶段。所以EventPublishingRunListener通过事件发布的方式通知注册的监听器应用程序的不同阶段,比如启动、环境准备、应用程序上下文准备、应用程序启动、运行以及失败等

php 复制代码
/**
 * Listener for the {@link SpringApplication} {@code run} method.
 * {@link SpringApplicationRunListener}s are loaded via the {@link SpringFactoriesLoader}
 * and should declare a public constructor that accepts a {@link SpringApplication}
 * instance and a {@code String[]} of arguments. A new
 * {@link SpringApplicationRunListener} instance will be created for each run.
 *
 * @author Phillip Webb
 * @author Dave Syer
 * @author Andy Wilkinson
 */
public interface SpringApplicationRunListener {
​
    /**
     * Called immediately when the run method has first started. Can be used for very
     * early initialization.
     在首次启动run方法时立即调用。 可用于非常早的初始化
     */
    void starting();
​
    /**
     * Called once the environment has been prepared, but before the
     * {@link ApplicationContext} has been created.
     * @param environment the environment
     在准备ApplicationContext之后,创建好ApplicationContext之前调用
     */
    void environmentPrepared(ConfigurableEnvironment environment);
​
    /**
     * Called once the {@link ApplicationContext} has been created and prepared, but
     * before sources have been loaded.
     * @param context the application context
     在创建和准备ApplicationContext之后,但在加载源之前调用
     */
    void contextPrepared(ConfigurableApplicationContext context);
​
    /**
     * Called once the application context has been loaded but before it has been
     * refreshed.
     * @param context the application context
      在ApplicationContext加载完之后但是在其刷新之前调用
     */
    void contextLoaded(ConfigurableApplicationContext context);
​
    /**
     * The context has been refreshed and the application has started but
     * {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner
     * ApplicationRunners} have not been called.
     * @param context the application context.
     * @since 2.0.0
     上下文已刷新,应用程序已启动,但CommandLineRunner 和ApplicationRunner 尚未被调用
     */
    void started(ConfigurableApplicationContext context);
​
    /**
     * Called immediately before the run method finishes, when the application context has
     * been refreshed and all {@link CommandLineRunner CommandLineRunners} and
     * {@link ApplicationRunner ApplicationRunners} have been called.
     * @param context the application context.
     * @since 2.0.0
     在刷新应用程序上下文并已调用所有CommandLineRunner和ApplicationRunner后,在run方法完成之前立即调用
     */
    void running(ConfigurableApplicationContext context);
​
    /**
     * Called when a failure occurs when running the application.
     * @param context the application context or {@code null} if a failure occurred before
     * the context was created
     * @param exception the failure
     * @since 2.0.0
     在应用程序启动或运行期间出现异常时调用。可以用于处理应用程序失败的情况。
     */
    void failed(ConfigurableApplicationContext context, Throwable exception);
​
}
​

事实上,在createSpringFactoriesInstances中还会调用构造方法从而创建实例,从上面我们知道这边找到了EventPublishingRunListener,因此会调用该类的构造方法

typescript 复制代码
@SuppressWarnings("unchecked")
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
       Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
       Set<String> names) {
    List<T> instances = new ArrayList<>(names.size());
    for (String name : names) {
       try {
          Class<?> instanceClass = ClassUtils.forName(name, classLoader);
          Assert.isAssignable(type, instanceClass);
          Constructor<?> constructor = instanceClass
                .getDeclaredConstructor(parameterTypes);
          // 调用构造方法创建实例
          T instance = (T) BeanUtils.instantiateClass(constructor, args);
          instances.add(instance);
       }
       catch (Throwable ex) {
          throw new IllegalArgumentException(
                "Cannot instantiate " + type + " : " + name, ex);
       }
    }
    return instances;
}

我们来看一下它的构造方法做了那些事情

kotlin 复制代码
private final SimpleApplicationEventMulticaster initialMulticaster;
​
public EventPublishingRunListener(SpringApplication application, String[] args) {
    this.application = application;
    this.args = args;
    this.initialMulticaster = new SimpleApplicationEventMulticaster();
    // 这边的application.getListeners() 在 new SpringApplication(primarySources).run(args)时保存了listeners,所以可以拿到注册的监听器
    for (ApplicationListener<?> listener : application.getListeners()) {
        // 存储在SimpleApplicationEventMulticaster的内部类中是一个set(继承了抽象类AbstractApplicationEventMulticaster)
       this.initialMulticaster.addApplicationListener(listener);
    }
}

该方法将加载到的监听器放入了容器中,先想一下这里的application.getListeners()从何而来?下面这段代码还记得吗,没错在SpringApplication构建时就加载了包括系统初始化器以及监听器,从而将这些监听器存入了SimpleApplicationEventMulticaster

kotlin 复制代码
    /**
     * Create a new {@link SpringApplication} instance. The application context will load
     * beans from the specified primary sources (see {@link SpringApplication class-level}
     * documentation for details. The instance can be customized before calling
     * {@link #run(String...)}.
     * @param resourceLoader the resource loader to use
     * @param primarySources the primary bean sources
     * @see #run(Class, String[])
     * @see #setSources(Set)
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        // 初始化器
        setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));
        // 监听器
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = deduceMainApplicationClass();
    }

接着我们来看看SimpleApplicationEventMulticaster又是什么

ApplicationEventMulticaster

scala 复制代码
/**
 * Simple implementation of the {@link ApplicationEventMulticaster} interface.
 *
 * <p>Multicasts all events to all registered listeners, leaving it up to
 * the listeners to ignore events that they are not interested in.
 * Listeners will usually perform corresponding {@code instanceof}
 * checks on the passed-in event object.
 *
 * <p>By default, all listeners are invoked in the calling thread.
 * This allows the danger of a rogue listener blocking the entire application,
 * but adds minimal overhead. Specify an alternative task executor to have
 * listeners executed in different threads, for example from a thread pool.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Stephane Nicoll
 * @see #setTaskExecutor
 */
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
}

首先SimpleApplicationEventMulticaster继承自AbstractApplicationEventMulticaster

kotlin 复制代码
/**
 * Abstract implementation of the {@link ApplicationEventMulticaster} interface,
 * providing the basic listener registration facility.
 *
 * <p>Doesn't permit multiple instances of the same listener by default,
 * as it keeps listeners in a linked Set. The collection class used to hold
 * ApplicationListener objects can be overridden through the "collectionClass"
 * bean property.
 *
 * <p>Implementing ApplicationEventMulticaster's actual {@link #multicastEvent} method
 * is left to subclasses. {@link SimpleApplicationEventMulticaster} simply multicasts
 * all events to all registered listeners, invoking them in the calling thread.
 * Alternative implementations could be more sophisticated in those respects.
 *
 * @author Juergen Hoeller
 * @author Stephane Nicoll
 * @since 1.2.3
 * @see #getApplicationListeners(ApplicationEvent, ResolvableType)
 * @see SimpleApplicationEventMulticaster
 */
public abstract class AbstractApplicationEventMulticaster
       implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
        
    private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);    
    final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);
    
    ...
    
    /**
     * Helper class that encapsulates a specific set of target listeners,
     * allowing for efficient retrieval of pre-filtered listeners.
     * <p>An instance of this helper gets cached per event type and source type.
     该类主要用于帮助 ApplicationEventMulticaster 的实现类管理监听器(listeners)和它们的订阅关系
     */
    private class ListenerRetriever {
​
        public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
​
        public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
​
        private final boolean preFiltered;
​
        public ListenerRetriever(boolean preFiltered) {
            this.preFiltered = preFiltered;
        }
​
        public Collection<ApplicationListener<?>> getApplicationListeners() {
            List<ApplicationListener<?>> allListeners = new ArrayList<>(
                    this.applicationListeners.size() + this.applicationListenerBeans.size());
            allListeners.addAll(this.applicationListeners);
            if (!this.applicationListenerBeans.isEmpty()) {
                BeanFactory beanFactory = getBeanFactory();
                for (String listenerBeanName : this.applicationListenerBeans) {
                    try {
                        ApplicationListener<?> listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
                        if (this.preFiltered || !allListeners.contains(listener)) {
                            allListeners.add(listener);
                        }
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        // Singleton listener instance (without backing bean definition) disappeared -
                        // probably in the middle of the destruction phase
                    }
                }
            }
            if (!this.preFiltered || !this.applicationListenerBeans.isEmpty()) {
                AnnotationAwareOrderComparator.sort(allListeners);
            }
            return allListeners;
        }
    }
}

AbstractApplicationEventMulticaster又实现了ApplicationEventMulticaster,该类提供了一些基本的、通用的方法和属性,如对 ApplicationListener 的管理(ListenerRetriever)等。

java 复制代码
/**
 * Interface to be implemented by objects that can manage a number of
 * {@link ApplicationListener} objects, and publish events to them.
 这是一个可以管理多个 ApplicationListener 对象并向它们发布事件的接口。
 这意味着它负责将事件传递给所有注册的监听器
 *
 * <p>An {@link org.springframework.context.ApplicationEventPublisher}, typically
 * a Spring {@link org.springframework.context.ApplicationContext}, can use an
 * ApplicationEventMulticaster as a delegate for actually publishing events.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Stephane Nicoll
 */
public interface ApplicationEventMulticaster {
​
    /**
     * Add a listener to be notified of all events.
     * @param listener the listener to add
     */
    void addApplicationListener(ApplicationListener<?> listener);
​
    /**
     * Add a listener bean to be notified of all events.
     * @param listenerBeanName the name of the listener bean to add
     */
    void addApplicationListenerBean(String listenerBeanName);
​
    /**
     * Remove a listener from the notification list.
     * @param listener the listener to remove
     */
    void removeApplicationListener(ApplicationListener<?> listener);
​
    /**
     * Remove a listener bean from the notification list.
     * @param listenerBeanName the name of the listener bean to add
     */
    void removeApplicationListenerBean(String listenerBeanName);
​
    /**
     * Remove all listeners registered with this multicaster.
     * <p>After a remove call, the multicaster will perform no action
     * on event notification until new listeners are being registered.
     */
    void removeAllListeners();
​
    /**
     * Multicast the given application event to appropriate listeners.
     * <p>Consider using {@link #multicastEvent(ApplicationEvent, ResolvableType)}
     * if possible as it provides a better support for generics-based events.
     * @param event the event to multicast
     */
    void multicastEvent(ApplicationEvent event);
​
    /**
     * Multicast the given application event to appropriate listeners.
     * <p>If the {@code eventType} is {@code null}, a default type is built
     * based on the {@code event} instance.
     * @param event the event to multicast
     * @param eventType the type of event (can be null)
     * @since 4.2
     */
    void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
​
}
​

ApplicationEventMulticaster 它允许对象管理一组 ApplicationListener 对象,并将事件发布给这些监听器

接着我们来看它是如何管理对象和发布事件的

回到代码EventPublishingRunListener#starting,代码流程为

SpringApplication#run -> listeners.starting() -> SpringApplicationRunListeners#starting -> listener.starting() -> EventPublishingRunListener#starting 该方法广播了一个事件,名为ApplicationStartingEvent,也就是multicastEvent方法的第一个参数

java 复制代码
private final SimpleApplicationEventMulticaster initialMulticaster;
@Override
public void starting() {
    this.initialMulticaster.multicastEvent(
          new ApplicationStartingEvent(this.application, this.args));
}

看一下SimpleApplicationEventMulticastermulticastEvent方法

less 复制代码
@Override
public void multicastEvent(ApplicationEvent event) {
    multicastEvent(event, resolveDefaultEventType(event));
}
​
@Override
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);
       }
    }
}

这两个方法需要传入ApplicationEvent事件

scala 复制代码
/**
 * Class to be extended by all application events. Abstract as it
 * doesn't make sense for generic events to be published directly.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 */
public abstract class ApplicationEvent extends EventObject {
​
    /** use serialVersionUID from Spring 1.2 for interoperability */
    private static final long serialVersionUID = 7099057708183571937L;
​
    /** System time when the event happened */
    private final long timestamp;
​
​
    /**
     * Create a new ApplicationEvent.
     * @param source the object on which the event initially occurred (never {@code null})
     */
    public ApplicationEvent(Object source) {
        super(source);
        this.timestamp = System.currentTimeMillis();
    }
​
​
    /**
     * Return the system time in milliseconds when the event happened.
     */
    public final long getTimestamp() {
        return this.timestamp;
    }
​
}

看一下该类的子类都有哪些

有没有觉得在哪里见过,没错这些子类事件正好对应了SpringApplicationRunListener定义的不同阶段

回到SimpleApplicationEventMulticaster#multicastEvent方法

less 复制代码
@Override
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);
       }
    }
}

整体来说该方法就做了两件事。首先根据事件类型获取该事件对应监听器,获取到对应监听器之后调用监听器的onApplicationEvent方法完成相应的动作

流程

最后来看下整体流程

  1. 方法启动时首先进入构造方法,构造方法会通过spring.factores文件找到ApplicationListener所有的实例并存储
  2. 构造器执行完毕进入run方法,同样的,在getRunListeners中会获取SpringApplicationRunListener的实现,也就是EventPublishingRunListener。还有调用EventPublishingRunListener的构造方法,保存上一步存储的监听器到内部容器中(AbstractApplicationEventMulticaster#ListenerRetriever)
  3. listeners.starting(),进入EventPublishingRunListener的starting方法并调用SimpleApplicationEventMulticaster的multicastEvent,这里会传入事件类型ApplicationStartingEvent
  4. multicastEvent方法会找到事件对应的监听器并调用监听器的onApplicationEvent

流程图如下(图片出自:github.com/coderbruis/...

相关推荐
后端小张23 分钟前
【JAVA 进阶】SpringBoot集成Sa-Token权限校验框架深度解析
java·spring boot·spring·架构·sa-token·springboot·权限框架
lang201509282 小时前
Spring Boot Actuator应用信息Application Information全解析
spring boot·后端·elasticsearch
paopaokaka_luck2 小时前
基于SpringBoot+Vue的DIY手工社预约管理系统(Echarts图形化、腾讯地图API)
java·vue.js·人工智能·spring boot·后端·echarts
计算机学姐6 小时前
基于微信小程序的高校班务管理系统【2026最新】
java·vue.js·spring boot·mysql·微信小程序·小程序·mybatis
摇滚侠10 小时前
Spring Boot 3零基础教程,WEB 开发 Thymeleaf 核心语法 笔记39
spring boot·笔记·后端·thymeleaf
九丶弟11 小时前
SpringBoot的cache使用说明
java·spring boot·spring·cache
lang2015092813 小时前
打造专属Spring Boot Starter
java·spring boot·后端
lang2015092815 小时前
Spring Boot RSocket:高性能异步通信实战
java·spring boot·后端
蹦跑的蜗牛16 小时前
Spring Boot使用Redis实现消息队列
spring boot·redis·后端
凤山老林17 小时前
SpringBoot 如何实现零拷贝:深度解析零拷贝技术
java·linux·开发语言·arm开发·spring boot·后端