SpringBoot启动监听SpringApplicationRunListener

命名我们就可以知道它是一个监听者,分析springboot启动流程我们会发现,它其实是用来在整个启动流程中接收不同执行点事件通知的监听者,SpringApplicationRunListener接口规定了SpringBoot的生命周期,在各个生命周期广播相应的事件,调用实际的ApplicationListener类。

源码分析

在这里插入图片描述

1.获取所有的监听器

SpringApplicationRunListeners可以理解为一个SpringApplicationRunListener的容器,他将SpringApplicationRunListener的集合以构造方法传入。并赋值给listeners成员变量,然后提供针对listeners成员变量的各种遍历操作方法。

private SpringApplicationRunListeners getRunListeners(String[] args) {
         // 构建class数组
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		// 调用SpringApplicationRunListener构造方法
		return new SpringApplicationRunListeners(logger,
				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
	}

SpringApplicationRunListeners 构造方法的第二个参数便是SpringApplicationRunListeners的集合,SpringApplication中调用构造方法时该参数是通过getSpringFactoriesInstances方法获取的,如下:
在这里插入图片描述

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
		// 获取类加载器
		ClassLoader classLoader = getClassLoader();
		// 加载META-INF/spring.factories中对应监听器配置,并将结果存于Set中(去重)
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		// 实例化监听器
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		// 排序
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

通过方法名便可得知,getSpringFactoriesInstances是用来获取factories配置文件中的注册类,并进行实例化操作。

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
				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;
	}

在上面代码中,实例化监听器时需要有一个默认的构造方法,且构造方法的参数为Class<?>[] parameterTypes。我们向上追踪该参数的来源,会发现该参数的值为Class数组,数组的内容依次为SpringApplication和String [].class。也就是说,SpringApplicationRunListener的实现类必须有默认的构造方法,且构造方法的参数必须依次为SpringApplication和String [].class。

2.SpringApplicationRunListener 源码分析

接口SpringApplicationRunListener是SpringApplication的run方法监听器。SpringApplicationRunListener 提供了一系列的方法,我们可以通过回调这些方法,在启动各个流程时加入指定的逻辑,SpringApplicationRunListener接口方法如下:

public interface SpringApplicationRunListener {

	/**
	 * 当run方法第一次被执行时,会被调用,可以用于非常早期的初始化工作
	 */
	default void starting() {
	}

	/**
	 * 当environment准备完成,在ConfigurableApplicationContext创建之前,该方法被调用
	 *
	 */
	default void environmentPrepared(ConfigurableEnvironment environment) {
	}

	/**
	 * 当ConfigurableApplicationContext构建完成,资源还未加载时,该方法被调用
	 *
	 */
	default void contextPrepared(ConfigurableApplicationContext context) {
	}

	/**
	 * 当ConfigurableApplicationContext加载完成,未被刷新之前,该方法被调用
	 *
	 */
	default void contextLoaded(ConfigurableApplicationContext context) {
	}

	/**
	 * 当ConfigurableApplicationContext刷新并启动后,CommandLineRunner和
	 * ApplicationRunner未执行之前,该方法被调用
	 */
	default void started(ConfigurableApplicationContext context) {
	}

	/**
	 * 当所有准备工作就绪,run方法执行完毕之前,该方法被调用
	 *
	 */
	default void running(ConfigurableApplicationContext context) {
	}

	/**
	 * 当应用程序出现错误时,该方法被调用
	 *
	 */
	default void failed(ConfigurableApplicationContext context, Throwable exception) {
	}

}

我们通过源码可以看出,SpringApplicationRunListener为run方法提供了各个运行阶段的监听事件处理功能。

3.实现类EventPublishingRunListener

EventPublishingRunListener是Spring Boot中针对SpringApplicationRunListener接口的唯一内建实现。EventPublishingRunListener使用内置的SimpleApplicationEventMulticaster来广播在上下文刷新之前触发的事件。
默认情况下,SpringBoot在初始化过程中触发的事件也是交由EventPublishingRunListener来代理实现的。EventPublishingRunListener的构造方法如下:

public EventPublishingRunListener(SpringApplication application, String[] args) {
        // 当前运行的SpringApplication实例
		this.application = application;
		// 启动程序时的命令参数
		this.args = args;
		// 创建SimpleApplicationEventMulticaster广播器
		this.initialMulticaster = new SimpleApplicationEventMulticaster();
		// 遍历ApplicationListener并关联SimpleApplicationEventMulticaster
		for (ApplicationListener<?> listener : application.getListeners()) {
			this.initialMulticaster.addApplicationListener(listener);
		}
	}

EventPublishingRunListener针对不同的事件停了不同的处理方法,但他们的处理流程基本相同。

@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));
	}	

在这里插入图片描述

  1. 程序启动到某个步骤后,调用EventPublishingRunListener的某个方法
  2. EventPublishingRunListener的具体方法将application参数和args参数封装到对应的事件中,这里的事件均为SpringApplicationEvent的实现类。
  3. 通过成员变量initialMulticaster的multicastEvent方法对事件进行广播。或者通过该方法的
    ConfigurableApplicationContext参数的publishEvent方法来对事件进行发布。
  4. 对应的ApplicationListener被触发,执行相应的业务逻辑
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringBoot中,我们可以通过实现监听器接口来监听启动事件。SpringBoot提供了两个监听器接口:CommandLineRunner和ApplicationRunner。这两个接口都需要标注@Component注解,并由IOC容器进行管理。在SpringBoot启动成功后,这两个接口的实现类中的回调方法会被执行。 具体来说,CommandLineRunner接口中有一个run方法,它会在所有的Bean都初始化之后、SpringApplication.run方法执行完成之前被调用。而ApplicationRunner接口中也有一个run方法,它会在CommandLineRunner接口的run方法执行完之后被调用。这意味着ApplicationRunner接口的实现类会在SpringBoot启动之后的最后阶段执行。 通过实现这两个接口,我们可以在SpringBoot启动成功后执行一些回调方法,用于资源的初始化或其他服务的启动监听器的执行顺序可以根据实现类的顺序来确定,实现类的顺序会影响回调方法的执行顺序。因此,我们可以根据业务需求,在不同的节点插入想要实现的代码,例如在服务器启动后加载缓存或动态修改环境变量中的参数等。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [SpringBoot启动监听](https://blog.csdn.net/jishanwang/article/details/88100499)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [SpringBoot各个监听启动执行顺序](https://blog.csdn.net/zhaojiyuan1024/article/details/124246752)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值