SpringApplicationRunListener监听器源码详解

 更新时间:2023年11月15日 09:20:25   作者:立小研先森  
这篇文章主要介绍了SpringApplicationRunListener监听器源码详解,springboot提供了两个类SpringApplicationRunListeners、SpringApplicationRunListener(EventPublishingRunListener),spring框架还提供了一个ApplicationListener接口,需要的朋友可以参考下

前言

springboot提供了两个类SpringApplicationRunListeners、SpringApplicationRunListener(EventPublishingRunListener),spring框架还提供了一个ApplicationListener接口,那么这几个类或接口的关系又是如何呢?

首先SpringApplicationRunListeners类是SpringApplicationRunListener接口的代理类,可以批量调用SpringApplicationRunListener接口方法,SpringApplicationRunListener接口只有一个实现类EventPublishingRunListener,其有一个属性SimpleApplicationEventMulticaster,SimpleApplicationEventMulticaster即是一个ApplicationListener监听器接口的代理实现类,可以批量的执行监听器的onApplicationEvent方法。

1.SpringApplicationRunListener接口源码

SpringApplicationRunListener是对org.springframework.boot.SpringApplication类的run方法进行监听,SpringApplicationRunListener实现类是通过SpringFactoriesLoader类加载(即springboot SPI);并且需要声明一个包含SpringApplication实例及String[]的参数构造方法。

public interface SpringApplicationRunListener {
	/**
	 * 当run方法第一次启动时立即调用,可用于非常早期的初始化
	 */
	default void starting() {
	}
	/**
	 * 在ApplicationContext创建之前,一旦环境environment准备好就调用。
	 * @param environment the environment
	 */
	default void environmentPrepared(ConfigurableEnvironment environment) {
	}
	/**
	 * 在资源(可以理解为配置主类)被加载完成之前,一旦ApplicationContext被创建并准备好就立马调用,
	 * @param context the application context
	 */
	default void contextPrepared(ConfigurableApplicationContext context) {
	}
	/**
	 * 在资源加载完成之后,但在刷新之前调用
	 * @param context the application context
	 */
	default void contextLoaded(ConfigurableApplicationContext context) {
	}
	/**
	 * 上下文已刷新,应用程序已启动,但是CommandLineRunner和ApplicationRunner尚未调用。
	 * @param context the application context.
	 * @since 2.0.0
	 */
	default void started(ConfigurableApplicationContext context) {
	}
	/**
	 * 当ApplicationContext已经refresh且所有的CommandLineRunner和ApplicationRunner都已被调用时,在run方法完成之前立即调用。
	 * @param context the application context.
	 * @since 2.0.0
	 */
	default void running(ConfigurableApplicationContext context) {
	}
	/**
	 * 在运行应用程序时发生故障时调用
	 * @param context 应用程序上下文,可能为null(在应用程序上下文创建之前)
	 * @param exception the failure
	 * @since 2.0.0
	 */
	default void failed(ConfigurableApplicationContext context, Throwable exception) {
	}

2.EventPublishingRunListener

SpringApplicationRunListener接口唯一实现类EventPublishingRunListener

public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
	//启动类实例对象
	private final SpringApplication application;
	//参数
	private final String[] args;
	//ApplicationListener监听器接口代理广播类
	private final SimpleApplicationEventMulticaster initialMulticaster;
	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);
		}
	}
}

其中application.getListeners()获取通过SPI方式定义的所有ApplicationListener监听器接口定义的监听器类,其初始化是在SpringApplication类中通过构造函数的方式,如下:

//监听器对象集合
private List<ApplicationListener<?>> listeners;

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();
  	//通过SPI方式初始化应用程序初始化器
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		//通过SPI方式获取ApplicationListener监听器
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

spring.factories配置文件:

# 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

3.SpringApplicationRunListeners

SpringApplicationRunListener接口实现类集合类SpringApplicationRunListeners

class SpringApplicationRunListeners {

	private final Log log;
	//存储SpringApplicationRunListener监听器集合
	private final List<SpringApplicationRunListener> listeners;

	SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
		this.log = log;
		this.listeners = new ArrayList<>(listeners);
	}
}

4.获取SpringApplicationRunListeners对象

org.springframework.boot.SpringApplication#run(java.lang.String…)方法中通过SPI方式获取SpringApplicationRunListeners对象

public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
    //通过SPI方式获取SpringApplicationRunListener监听器对象集合
		SpringApplicationRunListeners listeners = getRunListeners(args);
    //启动监听器,传递ApplicationStartingEvent事件
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      //environment准备好之后调用监听器environmentPrepared方法
      //传递ApplicationEnvironmentPreparedEvent事件
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
      //资源加载之前调用监听器的contextPrepared方法,传递ApplicationContextInitializedEvent事件
      //资源加载之后,refresh方法调用之前调用监听器的contextLoaded方法,传递ApplicationPreparedEvent事件
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
      //应用程序refresh之后调用,传递ApplicationStartedEvent事件
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
      //应用程序启动过程中出现异常调用failed方法
      //传递ApplicationFailedEvent事件
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}
		try {
      //在应用程序run方法运行结束之前调用,传递ApplicationReadyEvent事件
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}
	//通过SPI方式获取SpringApplicationRunListener接口实现类,并创建SpringApplicationRunListeners集合类
	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger,
				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
	}

spring.factories配置文件如下:

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

到此这篇关于SpringApplicationRunListener监听器源码详解的文章就介绍到这了,更多相关SpringApplicationRunListener监听器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java四种引用及在LeakCanery中应用详解

    java四种引用及在LeakCanery中应用详解

    这篇文章主要介绍了java四种引用及在LeakCanery中应用,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-09-09
  • HashSet和TreeSet使用方法的区别解析

    HashSet和TreeSet使用方法的区别解析

    这篇文章主要介绍了HashSet和TreeSet使用方法的区别解析,具有一定借鉴价值,需要的朋友可以参考下
    2018-01-01
  • JAVA数字千分位和小数点的现实代码(处理金额问题)

    JAVA数字千分位和小数点的现实代码(处理金额问题)

    这篇文章主要介绍了JAVA数字千分位和小数点的现实代码(处理金额问题),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10
  • 关于Mysql的四种存储引擎

    关于Mysql的四种存储引擎

    这篇文章主要介绍了关于Mysql的四种存储引擎,MySql的核心就是存储引擎,不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能,使用不同的存储引擎,还可以 获得特定的功能,需要的朋友可以参考下
    2023-05-05
  • 详解Java高并发编程之AtomicReference

    详解Java高并发编程之AtomicReference

    此篇文章主要介绍了AtomicReference的出现背景,AtomicReference的使用场景,以及介绍了AtomicReference的源码,重点方法的源码分析
    2021-06-06
  • Java ResultSet案例讲解

    Java ResultSet案例讲解

    这篇文章主要介绍了Java ResultSet案例讲解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • Jenkins自动部署SpringBoot项目实践教程

    Jenkins自动部署SpringBoot项目实践教程

    这篇文章主要介绍了Jenkins自动部署SpringBoot项目实践教程,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • 详解Java的Struts框架中上传文件和客户端验证的实现

    详解Java的Struts框架中上传文件和客户端验证的实现

    这篇文章主要介绍了Java的Struts框架中上传文件和客户端验证的实现,Struts是Java的SSH三大web开发框架之一,需要的朋友可以参考下
    2015-12-12
  • IDEA自定义Maven archetype的方法步骤

    IDEA自定义Maven archetype的方法步骤

    在创建Maven的项目时我们发现了一个很不方便的问题,就是每次创建Maven的工程的时候,都需要选择一个骨架,本文主要介绍了IDEA自定义Maven archetype的方法步骤,感兴趣的可以了解一下
    2022-03-03
  • Spring MVC学习教程之RequestMappingHandlerAdapter详解

    Spring MVC学习教程之RequestMappingHandlerAdapter详解

    这篇文章主要给大家介绍了关于Spring MVC学习教程之RequestMappingHandlerAdapter的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧
    2018-11-11

最新评论