基于架构
- Spring Cloud(微服务)
- Eureka(服务注册与发现)
- openFeign(远程调用)
问题出现
今天在使用CompletableFuture.runAsync()进行异步处理的情况下,在其内部的方法中有进行了服务之间的RPC远程调用,发生了报错,报错信息如下:
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [org.springframework.cloud.netflix.eureka.loadbalancer.EurekaLoadBalancerClientConfiguration]
2023-11-20T08:00:06.347980398Z at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:178) ~[spring-context-6.0.4.jar!/:6.0.4]
2023-11-20T08:00:06.347983603Z at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:398) ~[spring-context-6.0.4.jar!/:6.0.4]
2023-11-20T08:00:06.347986734Z at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:283) ~[spring-context-6.0.4.jar!/:6.0.4]
2023-11-20T08:00:06.348002958Z at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:344) ~[spring-context-6.0.4.jar!/:6.0.4]
2023-11-20T08:00:06.348007361Z at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:115) ~[spring-context-6.0.4.jar!/:6.0.4]
2023-11-20T08:00:06.348010447Z at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:745) ~[spring-context-6.0.4.jar!/:6.0.4]
2023-11-20T08:00:06.348013338Z at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:565) ~[spring-context-6.0.4.jar!/:6.0.4]
2023-11-20T08:00:06.348016094Z at org.springframework.cloud.context.named.NamedContextFactory.createContext(NamedContextFactory.java:138) ~[spring-cloud-context-4.0.1.jar!/:4.0.1]
2023-11-20T08:00:06.348018664Z at org.springframework.cloud.context.named.NamedContextFactory.getContext(NamedContextFactory.java:122) ~[spring-cloud-context-4.0.1.jar!/:4.0.1]
2023-11-20T08:00:06.348022604Z at org.springframework.cloud.context.named.NamedContextFactory.getInstances(NamedContextFactory.java:236) ~[spring-cloud-context-4.0.1.jar!/:4.0.1]
2023-11-20T08:00:06.348025371Z at org.springframework.cloud.openfeign.loadbalancer.RetryableFeignBlockingLoadBalancerClient.lambda$execute$2(RetryableFeignBlockingLoadBalancerClient.java:140) ~[spring-cloud-openfeign-core-4.0.1.jar!/:4.0.1]
2023-11-20T08:00:06.348028358Z at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:329) ~[spring-retry-2.0.0.jar!/:na]
2023-11-20T08:00:06.348030959Z at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:225) ~[spring-retry-2.0.0.jar!/:na]
2023-11-20T08:00:06.348033453Z at org.springframework.cloud.openfeign.loadbalancer.RetryableFeignBlockingLoadBalancerClient.execute(RetryableFeignBlockingLoadBalancerClient.java:135) ~[spring-cloud-openfeign-core-4.0.1.jar!/:4.0.1]
我的代码如下:
// 异步处理
CompletableFuture.runAsync(() -> asyncHandleImportAvatarAndPush(tempFile));
解决方法
注意:若出现这个问题,则必须配置自定义线程池!!!
例如:
// 其中asyncHandleImportAvatarAndPush为你需要处理的方法
CompletableFuture.runAsync(() -> asyncHandleImportAvatarAndPush(tempFile), taskExecutor);
这里给出我这边自定义线程池类供参考:
/**
* @Author: ou_sir
* @Description: 自定义线程池配置
* @Date: 2023/07/26
*/
@Slf4j
@Configuration
@EnableAsync
@EnableScheduling
public class TaskExecutorConfig implements SchedulingConfigurer, AsyncConfigurer {
// 线程池核心线程数
private static final int CORE_POOL_SIZE = 20;
// 线程池最大线程数
private static final int MAX_POOL_SIZE = 50;
// 线程池队列容量
private static final int QUEUE_CAPACITY = 99999;
/**
* 异步任务使用的线程池
*
* @return
*/
@Bean("taskExecutor")
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
// 配置核心线程数
taskExecutor.setCorePoolSize(CORE_POOL_SIZE);
// 配置最大线程数
taskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
// 配置队列大小
taskExecutor.setQueueCapacity(QUEUE_CAPACITY);
// 配置线程池中的线程的名称前缀
taskExecutor.setThreadNamePrefix("XXX-taskExecutor-");
// 线程池拒绝策略:当线程池队列已满时,新提交的任务由调用者所在的线程来执行
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有线程结束之后关闭线程池
taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
// 执行初始化
taskExecutor.initialize();
return taskExecutor;
}
/**
* 定时任务使用的线程池
*
* @return
*/
@Bean(destroyMethod = "shutdown", name = "taskScheduler")
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(10);
scheduler.setThreadNamePrefix("XXX-taskScheduler-");
scheduler.setAwaitTerminationSeconds(600);
scheduler.setWaitForTasksToCompleteOnShutdown(false);
return scheduler;
}
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
ThreadPoolTaskScheduler taskScheduler = taskScheduler();
scheduledTaskRegistrar.setTaskScheduler(taskScheduler);
}
@Override
public Executor getAsyncExecutor() {
return taskExecutor();
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (throwable, method, objects) -> {
log.error("异步任务执行出现异常, message {}, method {}, params {}", throwable, method, objects);
};
}
}
参考文章
https://blog.csdn.net/tergou/article/details/131400864