SpringBoot启动后的自定义初始化工作

本文介绍SpringBoot启动后如何通过自定义监听器监听ContextRefreshedEvent事件或实现ApplicationRunner/CommandLineRunner接口进行自定义初始化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

总述:

  • 自定义ContextRefreshedListener实现其onApplicationg()方法监听ContextRefreshedEvent事件。
  • 实现ApplicationRunner/CommandLineRunner接口的run()方法,可定义初始化顺序,且一定是应用程序启动最后一步执行。

1.启动后初始化

如何理解?

SpringBoot启动后,需要做一些业务相关的自定义的初始化工作。

2.SpringBoot启动后自定义初始化

2.1 自定义监听器监听ContextRefreshedEvent事件

代码如下:

@Component
public class ContextRefreshedListener implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        System.out.println("容器初始化结束,可以执行自定义初始化");
    }
}

输出如下: 

为什么在自定义监听器当中可以执行自定义初始化工作?

(1)对于ContextRefreshedEvent事件:

在SpringBoot程序启动过程中,ContextRefreshedEvent事件在容器初始化完成后会被发布。这意味着在SpringBoot启动结束后,可以通过自定义监听器监听ContextRefreshedEvent事件,然后在自定义监听器重写的onApplication方法中进行初始化操作。

代码如下:

//程序启动主要方法
public ConfigurableApplicationContext run(String... args) {
        //...
		refreshContext(context);
		//...
		return context;
	}

//容器刷新主要方法
public void refresh() throws BeansException, IllegalStateException {
		//...
				// Last step: publish corresponding event.
				finishRefresh();
//...
			}


	protected void finishRefresh() {
//...
		// Publish the final event.
		publishEvent(new ContextRefreshedEvent(this));//发布ContextRefreshedEvent事件
//...
	}

(2)对于自定义监听器ContextRefreshedListener:

        所有自定义监听器都需要实现ApplicationListener的onApplication()方法,这里用于自定义初始化的ContextRefreshedListener自定义监听器,只是监听了容器启动快结束时候的ContextRefreshedEvent事件。

        SpringBoot在初始化 ApplicationContext 的时候,会从当前的 bean 中找到 ApplicationListener 类型的 bean,将这些 bean 注册到 ApplicationContext 的事件发布器上,具体实现原理见这篇文章

protected void registerListeners() {
  ...
  String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
  for (String listenerBeanName : listenerBeanNames) {
    getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
  }
  ..
}

2.2 实现ApplicationRunner/CommandLineRunner接口的run方法

这两个接口是SpringBoot提供的专门用于初始化的,只需要实现他们的run()方法即可。此外,还可以在上述2个接口实现类上加入Order注解,以达到顺序初始化的目的。

@Order(1)
@Component
public class AppStartupRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("初始化代码");
    }
}

有了前面自定义ContextRefreshedListener监听器,为什么还要提供这两个初始化接口?

为了将context当中监听器和初始化做隔离。面提到的ContextRefreshedEvent事件和对应的自定义ContextRefreshedListener监听器,本质上还是利用事件监听器做初始化。而ApplicationRunner

和CommandLineRunner接口是专门用于初始化工作的接口。

此外,上述2个接口在应用启动过程中,必定是在SpringBoot程序启动的最后一步调用的,源码如下:

public ConfigurableApplicationContext run(String... args) {
		//...
			callRunners(context, applicationArguments);
}

callRunners具体实现:


	private void callRunners(ApplicationContext context, ApplicationArguments args) {
		List<Object> runners = new ArrayList<>();
		runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
		runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
		AnnotationAwareOrderComparator.sort(runners);//按照order排序
		for (Object runner : new LinkedHashSet<>(runners)) {
			if (runner instanceof ApplicationRunner) {
        //先执行实现ApplicationRunner接口的自定义runner
				callRunner((ApplicationRunner) runner, args);
			}
			if (runner instanceof CommandLineRunner) {
				callRunner((CommandLineRunner) runner, args);
			}
		}
	}

 最终实现其实还是调用runner.run()方法:

(runner).run(args);

2.3 ApplicationRunner和CommandRunner接口有什么区别?

这两个接口的不同之处在于:ApplicationRunner 中 run 方法的参数封装为了ApplicationArguments对象,而CommandLineRunner接口中run方法的参数为String数组。

源码对比如下:

public interface ApplicationRunner {
	void run(ApplicationArguments args) throws Exception;
}


public interface CommandLineRunner {
	void run(String... args) throws Exception;
}

参考链接:

https://zhuanlan.zhihu.com/p/352967633

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值