升级至Java17+Tomcat10+SpringBoot3后ForkJoinPool加载类路径资源失败
问题解决:Tomcat 10中ForkJoinPool线程加载类路径资源失败
核心原因
Tomcat 10(基于Jakarta EE 9+)的类加载机制与Tomcat 8存在差异,且ForkJoinPool的工作线程默认使用系统类加载器,而非Web应用专属的类加载器。普通Thread/ExecutorService的线程会继承父线程(Web请求线程)的上下文类加载器(对应WEB-INF/classes的类加载器),但ForkJoinPool的线程池是提前初始化的,无法自动继承Web应用的类加载上下文,导致找不到classpath下的资源。
解决方案
1. 显式设置ForkJoinPool任务的上下文类加载器
在提交到ForkJoinPool的任务中,手动将线程的上下文类加载器设置为当前Web应用的类加载器,再执行资源加载逻辑:
// 在Web请求线程中获取当前应用的类加载器 ClassLoader appClassLoader = Thread.currentThread().getContextClassLoader(); ForkJoinPool forkJoinPool = new ForkJoinPool(); forkJoinPool.submit(() -> { // 强制设置上下文类加载器为Web应用类加载器 Thread.currentThread().setContextClassLoader(appClassLoader); // 加载字体文件示例 try (InputStream fontStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("fonts/your-font.ttf")) { // 资源处理逻辑 } catch (IOException e) { e.printStackTrace(); } }).join();
2. 使用Spring Boot的ResourceLoader加载资源(推荐)
Spring Boot 3的ResourceLoader会自动绑定Web应用的类加载器,无需手动处理上下文,兼容性更强:
// 注入Spring的ResourceLoader @Autowired private ResourceLoader resourceLoader; // 在ForkJoinPool任务中加载资源 ForkJoinPool forkJoinPool = new ForkJoinPool(); forkJoinPool.submit(() -> { try { Resource fontResource = resourceLoader.getResource("classpath:fonts/your-font.ttf"); try (InputStream fontStream = fontResource.getInputStream()) { // 资源处理逻辑 } } catch (IOException e) { e.printStackTrace(); } }).join();
3. 验证资源路径与打包结果
- 解压WAR包确认
fonts目录确实存在于WEB-INF/classes下 - 资源路径使用
classpath:fonts/xxx.ttf格式,避免开头加斜杠(如/fonts/xxx.ttf会导致路径解析错误)
内容的提问来源于stack exchange,提问作者Raffa
相关产品推荐
相关产品推荐

