基本概念

监听器模型
  • 监听器模型四要素:
    • 事件
    • 监听器
    • 广播器
    • 触发机制

系统事件

  • 核心类图:
    系统事件类图

ApplicationFailedEvent

  • 可以通过ApplicationFailedEvent 获取Throwable实例对象获取异常信息并处理。
public class ShareniuApplicationFailedEventListener implements ApplicationListener<ApplicationFailedEvent> {
    @Override
    public void onApplicationEvent(ApplicationFailedEvent event) {
        System.out.println("--------------:ShareniuApplicationFailedEventListener");
        Throwable exception = event.getException();
        System.out.println(exception);
    }
}

ApplicationStartingEvent

  • 通知框架启动
public ApplicationStartingEvent(SpringApplication application, String[] args) {
    super(application, args);
}

ApplicationEnvironmentPreparedEvent

  • 在启动流程的run()方法中调用prepareEnvironment()方法构建环境environment,将构建好的environment传递给enviromnmentPrepared()方法从而发布ApplicationEnvironmentPreparedEvent事件,代表环境已构建完毕。
  • Environment:表示当前应用程序正在其中运行的环境,核心功能是提供profile和properties给应用查询,Profile就是Spring Boot可以对不同环境或者指令来读取不同的配置文件,properties包括 properties files, JVM system properties, system environment variables, JNDI, servlet context parameters, ad-hoc Properties objects,Maps等。
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
		ApplicationArguments applicationArguments) {
	    //创建环境,这里是根据web应用类型返回的,得到的是一个标准基于servlet的web环境
	ConfigurableEnvironment environment = getOrCreateEnvironment();
        //配置环境(属性源、配置文件),参数是上一步创建的environment和原始args参数
	configureEnvironment(environment, applicationArguments.getSourceArgs());
        //发布事件ApplicationEnvironmentPreparedEvent
	listeners.environmentPrepared(environment);
        //将spring.main配置绑定到SpringApplication
	bindToSpringApplication(environment);
        //isCustomEnvironment默认为false,如果你通过SpringApplication对象的setEnvironment()方法设置了环境,该值变为true,直接跳过这里
        //转换为标准环境
	if (!this.isCustomEnvironment) {
		environment = new EnvironmentConverter(getClassLoader())
				.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
	}
	ConfigurationPropertySources.attach(environment);
	return environment;
}
  • ApplicationEnvironmentPreparedEvent事件中包含已经设置好的环境,其主要目的是加载配置文件,初始化日志系统等。
public class ApplicationEnvironmentPreparedEvent extends SpringApplicationEvent {
	private final ConfigurableEnvironment environment;
	public ApplicationEnvironmentPreparedEvent(SpringApplication application,
			String[] args, ConfigurableEnvironment environment) {
		super(application, args);
		this.environment = environment;
	}
	public ConfigurableEnvironment getEnvironment() {
		return this.environment;
	}
}

ApplicationContextInitializedEvent

  • 通知创建上下文完毕,可以进行后续配置。context是spring的上下文,主要是Spring的一些配置信息,Bean、Resource等。
public ApplicationContextInitializedEvent(SpringApplication application, String[] args,
        ConfigurableApplicationContext context) {
    super(application, args);
    this.context = context;
}

ApplicationPreparedEvent

  • 通知上下文加载完毕。
public ApplicationPreparedEvent(SpringApplication application, String[] args,
        ConfigurableApplicationContext context) {
    super(application, args);
    this.context = context;
}

ApplicationStartedEvent

  • 通知上下文已可以使用,即将启动,可以在启动前进行一些设置。
public ApplicationStartedEvent(SpringApplication application, String[] args,
        ConfigurableApplicationContext context) {
    super(application, args);
    this.context = context;
}

ApplicationReadyEvent

  • 通知上下文已经准备完毕并正在运行。
public ApplicationReadyEvent(SpringApplication application, String[] args, ConfigurableApplicationContext context) {
    super(application, args);
    this.context = context;
}

触发机制

  • 事件发送顺序
    1. failed:框架启动失败,发出ApplicationFailedEvent
    2. starting:框架开始启动,发出ApplicationStartingEvent
    3. environmentPrepared:环境准备完成,发出ApplicationEnvironmentPreparedEvent
    4. contextInitialized:上下文创建完成,发出ApplicationContextInitializedEvent
    5. prepared:上下文加载完成,发出ApplicationPreparedEvent
    6. started:上下文可以使用,即将运行,发出ApplicationStartedEvent
    7. ready:框架正在运行,发出ApplicationReadyEvent
  • 获取监听器列表
    1. start
    2. getApplicationListeners
    3. 是否有缓存,是则读取缓存并返回,否则继续
    4. retrieveApplicationListeners
    5. 遍历监听器
    6. supportsEvent(start)
      1. supportsEventType
      2. 是否SmartApplicationListener类型
        1. 否->实现接口类型变量是否事件同类或子类->是
        2. 是->实现类是否supportEventType->是
      3. supportsSourceType
      4. 是否SmartApplicationListener类型
        1. 否->true
        2. 是->实现类是否supportsSourceType->是->true
    7. 加入符合条件监听器列表
    8. end

源码分析

  • 在SpringApplication构造函数中通过以下代码从spring.factories中加载出ApplicationListener事件监听接口的SPI扩展实现类然后添加到SpringApplication对象的listeners集合中,用于后续监听SpringBoot启动过程中的事件,来执行一些初始化逻辑工作。
    • 服务提供者接口(Service Provider Interface,SPI),它提供为某个接口寻找服务实现的机制。当服务的提供者提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  • 在SpringBoot的启动过程(run()方法)中首先会先新建一个SpringApplicationRunListeners对象用于发射SpringBoot启动过程中的生命周期事件。
SpringApplicationRunListeners listeners = getRunListeners(args);
-----------------------------------------------------------------------
private SpringApplicationRunListeners getRunListeners(String[] args) {
    // 构造一个由SpringApplication.class和String[].class组成的types
    Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
    // 1) 根据SpringApplicationRunListener接口去spring.factories配置文件中加载其SPI扩展实现类
    // 2) 构建一个SpringApplicationRunListeners对象并返回
    return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
            SpringApplicationRunListener.class, types, this, args));
}
  • 上面的代码会在getSpringFactoriesInstances中加载SpringApplicationRunListener唯一一个SPI实现类EventPublishingRunListener。由它在SpringBoot启动过程的不同阶段发射不同的SpringBoot的生命周期事件,即SpringApplicationRunListeners对象没有承担广播事件的职责,而是委托EventPublishingRunListener来广播事件的。
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {

    private final SpringApplication application;

    private final String[] args;
    // 拥有一个SimpleApplicationEventMulticaster事件广播器来广播事件
    private final SimpleApplicationEventMulticaster initialMulticaster;

    public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
        // 新建一个事件广播器SimpleApplicationEventMulticaster对象
        this.initialMulticaster = new SimpleApplicationEventMulticaster();
        // 遍历在构造SpringApplication对象时从spring.factories配置文件中获取的事件监听器
        for (ApplicationListener<?> listener : application.getListeners()) {
            // 将从spring.factories配置文件中获取的事件监听器们添加到事件广播器initialMulticaster对象的相关集合中
            this.initialMulticaster.addApplicationListener(listener);
        }
    }

    @Override
    public int getOrder() {
        return 0;
    }
    // 发射ApplicationStartingEvent事件
    @Override
    public void starting() {
        this.initialMulticaster.multicastEvent(
                new ApplicationStartingEvent(this.application, this.args));
    }
    // 发射ApplicationEnvironmentPreparedEvent事件
    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
        this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
                this.application, this.args, environment));
    }
    // 发射ApplicationContextInitializedEvent事件
    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent(
                this.application, this.args, context));
    }
    // 发射ApplicationPreparedEvent事件
    @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));
    }
    // 发射ApplicationStartedEvent事件
    @Override
    public void started(ConfigurableApplicationContext context) {
        context.publishEvent(
                new ApplicationStartedEvent(this.application, this.args, context));
    }
    // 发射ApplicationReadyEvent事件
    @Override
    public void running(ConfigurableApplicationContext context) {
        context.publishEvent(
                new ApplicationReadyEvent(this.application, this.args, context));
    }
    // 发射ApplicationFailedEvent事件
    @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);
        }
    }
    
    // ...省略非关键代码
}
  • EventPublishingRunListener类有一个SimpleApplicationEventMulticaster的属性,即EventPublishingRunListener对象没有承担广播事件的职责,而是委托SimpleApplicationEventMulticaster来广播事件的。它通过multicastEvent来广播事件。
    广播器类图
@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);
        }
    }
}