CommandLineRunner、ApplicationRunner of SpringBoot

本文介绍了SpringBoot中CommandLineRunner和ApplicationRunner接口的区别及使用方法。这两个接口允许开发者在Spring容器启动时执行特定任务,如配置初始化等。文章还提供了简单的示例代码,并详细解释了这些接口如何被调用。

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

如果需要在容器启动的时候就开始执行一些内容。比如配置初始化等,SpringBoot提供的这个接口就是干这个的。同时,通过其源码发现,它还提供了另外一个有同样功能的接口叫ApplicationRunner。两者的区别在于所接受的参数类型不一样。

CommandLineRunner的run方法定义如下:

/**
	 * Callback used to run the bean.
	 * @param args incoming main method arguments
	 * @throws Exception on error
	 */
	void run(String... args) throws Exception;

而ApplicationRunner的定义如下:

/**
	 * Callback used to run the bean.
	 * @param args incoming application arguments
	 * @throws Exception on error
	 */
	void run(ApplicationArguments args) throws Exception;

其他方面没什么区别。都是在容器启动时做指定动作。

简单使用示例:

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class Application implements CommandLineRunner {

	@Autowired
	CollectorExecRateService collectorExecRateService;

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

	@Override
	public void run(String... strings) throws Exception {
		DefaultExports.initialize();
		//do something you need
	}
}

最后,对于CommandLineRunner中run方法的执行时机,是在Spring容器完全启动完成的时候被执行。

看下源码中的说明:( 源码位置:SpringApplication.run(String... args),springboot版本:2.0.2 )

try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(
					SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
            //这里是去调用CommandLineRunner or ApplicationRunner的run方法
			callRunners(context, applicationArguments);
		}

callRunners的方法很简单,就是排序后执行run方法:

private void callRunners(ApplicationContext context, ApplicationArguments args) {
		List<Object> runners = new ArrayList<>();
        //注册所有实现两个接口的class
		runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
		runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
		//根据order排序
        AnnotationAwareOrderComparator.sort(runners);
        //遍历所有注册的方法,执行其内容
		for (Object runner : new LinkedHashSet<>(runners)) {
			if (runner instanceof ApplicationRunner) {
                //执行ApplicationRunner中的run
				callRunner((ApplicationRunner) runner, args);
			}
			if (runner instanceof CommandLineRunner) {
                //执行CommandLineRunner中的run
				callRunner((CommandLineRunner) runner, args);
			}
		}
	}


    //执行ApplicationRunner
    private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
		try {
			(runner).run(args);
		}
		catch (Exception ex) {
			throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
		}
	}
    //执行CommandLineRunner
	private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
		try {
			(runner).run(args.getSourceArgs());
		}
		catch (Exception ex) {
			throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
		}
	}

 

<think>好的,我需要解决用户关于Java应用中出现的IllegalStateException异常,特别是涉及ApplicationRunner的问题。首先,我得仔细分析用户提供的引用内容,找出可能的原因和解决方案。 用户提到了几个引用,其中引用1、2、5提到了ApplicationRunnerCommandLineRunner执行失败。常见的原因可能有Bean初始化问题、循环依赖、配置错误等。比如,ApplicationRunner的run方法中如果有未处理的异常,会导致这个错误,需要检查相关代码是否有异常抛出。另外,如果Spring Boot的配置类找不到,比如引用3中的情况,可能是因为测试类的位置不对,或者缺少@SpringBootConfiguration注解。这时候需要调整包结构或明确指定配置类。 另外,引用4提到加载ApplicationContext失败,可能是因为配置文件缺失或路径错误,需要检查@ContextConfiguration的locations是否正确引入了所有需要的配置文件。可能用户在整合多个配置文件时遗漏了某些,导致配置不完整,从而引发异常。 接下来,我需要把这些可能的原因整理出来,并给出对应的解决方案。比如,检查ApplicationRunner实现类中的代码是否有异常,确保配置类正确加载,处理循环依赖,检查配置文件路径等。同时,用户可能需要了解如何排查日志,找到具体的异常堆栈信息,这样才能准确定位问题所在。 另外,用户可能遇到的类似问题,比如CommandLineRunner的失败,可以一并说明,因为两者的处理方式相似。需要提醒用户在启动时注意Bean的加载顺序和依赖关系,避免在初始化过程中出现不可预料的错误。 最后,生成的相关问题需要覆盖常见的相关异常场景,比如配置类找不到、上下文加载失败、循环依赖等,帮助用户扩展了解其他可能遇到的异常情况及其解决方法。</think>### java.lang.IllegalStateException: Failed to execute ApplicationRunner 异常原因及解决方案 #### 一、异常原因分析 1. **ApplicationRunner实现类中存在未处理的异常** `ApplicationRunner`的`run()`方法执行时抛出异常(如空指针、资源加载失败等),导致Spring Boot应用启动失败[^1][^5]。 2. **配置类加载失败** - 测试类未正确指定`@SpringBootTest(classes=主配置类.class)`,导致找不到`@SpringBootConfiguration`[^3] - 配置文件路径错误或缺失,如XML配置文件未正确引入(需检查`@ContextConfiguration(locations={...})`的完整性)[^4] 3. **Bean初始化顺序问题** 在`ApplicationRunner`执行时依赖的Bean尚未完成初始化,例如数据库连接池未就绪或缓存未加载[^2][^5]。 4. **循环依赖或上下文关闭** Spring上下文在初始化过程中被意外关闭,或存在循环依赖导致Bean创建失败[^2]。 --- #### 二、解决方案 1. **排查ApplicationRunner实现类** ```java @Component public class MyRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) { try { // 业务代码 } catch (Exception e) { log.error("Runner执行失败", e); // 添加异常捕获 } } } ``` 使用`try-catch`捕获并记录异常,避免启动流程中断[^1]。 2. **修复配置类路径问题** - 测试类明确指定主配置类: ```java @SpringBootTest(classes = MyApplication.class) public class MyTest { ... } ``` - 多配置文件场景需完整引入: ```java @ContextConfiguration(locations = { "classpath:config/application-core.xml", "classpath:config/application-db.xml" }) ``` 3. **调整Bean初始化顺序** 使用`@DependsOn`注解强制依赖顺序: ```java @Bean @DependsOn("dataSource") // 确保数据源先初始化 public MyService myService() { ... } ``` 4. **检查依赖注入完整性** 通过启动日志排查以下问题: ```log *************************** APPLICATION FAILED TO START *************************** Description: A component required a bean of type 'com.example.ServiceA' that could not be found. Action: Consider defining a bean of type 'com.example.ServiceA' in your configuration. ``` --- #### 三、调试建议 1. **启用DEBUG日志** 在`application.properties`中添加: ```properties logging.level.root=DEBUG ``` 可获取更详细的Bean加载和初始化信息。 2. **使用断点调试** 在`ApplicationRunner.run()`方法入口设置断点,逐步跟踪执行流程。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值