项目场景
项目场景:这是一个任务的下发接口,这个任务是个复杂的功能,涉及到多次调用外部接口,处理时长比较长,所以在下发接口做了一个异步。
问题描述
使用异步方法:
CompletableFuture.runAsync(() -> {
// todo something
});
在该任务涉及到公司封装的定时任务管理类时,提示部分class 找不到。类似以下的报错。
Caused by: java.lang.ClassNotFoundException: aac.tt.abac.ScheduleTask
at jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) ~[?:?]
at jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) ~[?:?]
at java.lang.ClassLoader.loadClass(ClassLoader.java:521) ~[?:?]
at java.lang.Class.forName0(Native Method) ~[?:?]
at java.lang.Class.forName(Class.java:495) ~[?:?]
at java.lang.Class.forName(Class.java:474) ~[?:?]
at org.springframework.util.ClassUtils.forName(ClassUtils.java:291) ~[spring-core-6.0.21.jar:6.0.21]
at org.springframework.scheduling.quartz.ResourceLoaderClassLoadHelper.loadClass(ResourceLoaderClassLoadHelper.java:81) ~[spring-context-support-6.0.21.jar:6.0.21]
at org.springframework.scheduling.quartz.ResourceLoaderClassLoadHelper.loadClass(ResourceLoaderClassLoadHelper.java:87) ~[spring-context-support-6.0.21.jar:6.0.21]
at org.quartz.impl.jdbcjobstore.StdJDBCDelegate.selectJobDetail(StdJDBCDelegate.java:852) ~[quartz-2.3.1.jar:?]
at org.quartz.impl.jdbcjobstore.JobStoreSupport.retrieveJob(JobStoreSupport.java:1390) ~[quartz-2.3.1.jar:?]
at org.quartz.impl.jdbcjobstore.JobStoreSupport.storeTrigger(JobStoreSupport.java:1210) ~[quartz-2.3.1.jar:?]
Caused by: org.quartz.JobPersistenceException: Couldn't retrieve job because a required class was not found:
原因分析
开始以为是未在启动类配置该包的扫描,但是检查了一遍发现都配了。
测试了一下不使用异步方法,发现不会报错了。
大概原因就是CompletableFuture.runAsync 异步方法导致spring应用上下文缺失,
后面查了一下相关资料:
Spring 管理的 Bean 中调用 CompletableFuture.runAsync 时,默认情况下,这个异步任务会在 ForkJoinPool.commonPool() 中执行,而不是在 Spring 应用上下文中。这意味着在这个新线程中,Spring 的依赖注入和 AOP 代理等特性将不可用
解决方案
- 可以新建一个线程来执行。
- 使用@Async注解
- 自定义 Executor:你可以创建一个自定义的 Executor 并将其配置为 Spring 的 TaskExecutor,这样可以确保在异步任务中仍然能够访问 Spring 的上下文。
@Configuration
public class AsyncConfig {
@Bean
public Executor taskExecutor() {
return Executors.newFixedThreadPool(10);
}
}
// 在你的服务类中使用自定义的 Executor
@Service
public class MyService {
private final Executor executor;
@Autowired
public MyService(Executor executor) {
this.executor = executor;
}
public void doSomethingAsync() {
CompletableFuture.runAsync(() -> {
// 异步任务
System.out.println("Running in a separate thread with runAsync");
}, executor);
}
}
- 也许还有其他方法,可以提供给我,非常感谢。
若您有任何看法、疑问或补充,欢迎在下方留言区畅所欲言,我非常期待与您深入交流。您的评论将让这个话题更加丰富多彩。
如果这篇文章对您有长期参考价值,不妨点击收藏按钮,方便日后随时查阅。