SpringBoot升级后实现AsyncConfigurer致Bean实例化失败问题排查
问题描述
将SpringBoot版本从2.1.2升级至2.7.16、SpringCloud版本从2.1.2.RELEASE升级至2021.0.4.0后,项目启动出现如下异常:
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [java.util.concurrent.Executor]: Illegal arguments to factory method 'getAsyncExecutor'; args: ; nested excep
配置代码如下:
@EnableAsync @Configuration public class ExecutorConfig implements AsyncConfigurer { private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class); @Primary @Override @Bean public Executor getAsyncExecutor() { ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor(); // 设置核心线程数 threadPool.setCorePoolSize(10); // 设置最大线程数 threadPool.setMaxPoolSize(100); // 线程池所使用的缓冲队列 threadPool.setQueueCapacity(250); // 等待任务在关机时完成--表明等待所有线程执行完 threadPool.setWaitForTasksToCompleteOnShutdown(true); // 等待时间 (默认为0,此时立即停止),并没等待xx秒后强制停止 threadPool.setAwaitTerminationSeconds(60); // 线程名称前缀 threadPool.setThreadNamePrefix("MyAsync-"); // 初始化线程 threadPool.initialize(); return threadPool; } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new MyAsyncExceptionHandler(); } /** * 自定义异常处理类 * * @author hry * */ class MyAsyncExceptionHandler implements AsyncUncaughtExceptionHandler { // 手动处理捕获的异常 @Override public void handleUncaughtException(Throwable throwable, Method method, Object... obj) { System.out.println("-------------》》》捕获线程异常信息"); logger.info("Exception message - " + throwable.getMessage()); logger.info("Method name - " + method.getName()); for (Object param : obj) { logger.info("Parameter value - " + param); } } } }
移除AsyncConfigurer接口实现后项目可正常启动,请问原因是什么?
原因分析
- 注解冲突:Spring Boot 2.6+(对应Spring Cloud 2021.x版本)之后,
AsyncConfigurer的实现类会被Spring异步框架自动识别,用来配置默认异步执行器。但你给getAsyncExecutor()方法同时加了@Bean注解,导致Spring把这个接口方法当成Bean的工厂方法处理,两者的参数匹配逻辑冲突,最终触发"非法参数"的实例化异常。 - 手动初始化问题:
ThreadPoolTaskExecutor在Spring 2.6+版本中,容器会自动管理它的初始化和销毁流程,手动调用initialize()会导致线程池重复初始化,进一步加剧Bean创建过程中的异常。
解决方案
方案1:保留AsyncConfigurer实现,调整注解和初始化逻辑
去掉getAsyncExecutor()上的@Bean和@Primary注解,同时移除手动调用的threadPool.initialize():
@EnableAsync @Configuration public class ExecutorConfig implements AsyncConfigurer { private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class); @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor(); threadPool.setCorePoolSize(10); threadPool.setMaxPoolSize(100); threadPool.setQueueCapacity(250); threadPool.setWaitForTasksToCompleteOnShutdown(true); threadPool.setAwaitTerminationSeconds(60); threadPool.setThreadNamePrefix("MyAsync-"); // 移除手动初始化调用 return threadPool; } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new MyAsyncExceptionHandler(); } class MyAsyncExceptionHandler implements AsyncUncaughtExceptionHandler { @Override public void handleUncaughtException(Throwable throwable, Method method, Object... obj) { System.out.println("-------------》》》捕获线程异常信息"); logger.info("Exception message - " + throwable.getMessage()); logger.info("Method name - " + method.getName()); for (Object param : obj) { logger.info("Parameter value - " + param); } } } }
方案2:如果需要将线程池作为Bean注入其他组件
单独定义@Bean方法暴露线程池,和AsyncConfigurer的实现分离:
@EnableAsync @Configuration public class ExecutorConfig implements AsyncConfigurer { private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class); @Override public Executor getAsyncExecutor() { return createAsyncExecutor(); } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new MyAsyncExceptionHandler(); } // 单独定义Bean供其他地方注入 @Primary @Bean(name = "myAsyncExecutor") public Executor asyncExecutorBean() { return createAsyncExecutor(); } // 抽取线程池创建逻辑 private ThreadPoolTaskExecutor createAsyncExecutor() { ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor(); threadPool.setCorePoolSize(10); threadPool.setMaxPoolSize(100); threadPool.setQueueCapacity(250); threadPool.setWaitForTasksToCompleteOnShutdown(true); threadPool.setAwaitTerminationSeconds(60); threadPool.setThreadNamePrefix("MyAsync-"); return threadPool; } class MyAsyncExceptionHandler implements AsyncUncaughtExceptionHandler { @Override public void handleUncaughtException(Throwable throwable, Method method, Object... obj) { System.out.println("-------------》》》捕获线程异常信息"); logger.info("Exception message - " + throwable.getMessage()); logger.info("Method name - " + method.getName()); for (Object param : obj) { logger.info("Parameter value - " + param); } } } }
内容的提问来源于stack exchange,提问作者polyphylla
相关产品推荐
相关产品推荐

