ClassLoader在dev环境无法加载到配置文件问题
问题排查过程
背景
一模块使用第三方提供的sdk, 在本地运行ok, 与关联方联调成功, 但部署到dev后无法调通
排查过程
排查整个联调链路, 网络无问题, 关联方无问题, 问题定位到请求方, 即我方模块
由于本地代码没有问题, 本地运行的是编译后的代码, dev运行的是部署后的代码, 两者最大的差距可能就是打包后的配置问题
- 本地打jar包运行, 排查是否是容器环境问题, 结果是本地打的jar包依旧请求不到关联方
- 排查打包后相关配置文件的加载, 确认到sdkjar包中的配置信息加载不到, sdk有问题
- 定位到问题源码
解决方案
- 改用Thread.currentThread().getContextClassLoader()
- 改CfgUtil类, 然后编译成class文件, 替换sdk的这个文件, 然后重新打包(这里直接打zip改成jar后缀就行)上传私服即可
原理解析
类加载器 | 父加载器 | 负责加载的类路径 | 用途与特点 |
---|---|---|---|
BootstrapClassLoader | null (最顶层) | JVM 核心类库:``- $JAVA_HOME/jre/lib - -Xbootclasspath 指定的路径 | 由 C++ 实现,加载 Java 核心类(如 java.lang.* ),无法直接操作。 |
ExtClassLoader | BootstrapClassLoader | 扩展类路径:``- $JAVA_HOME/jre/lib/ext - -Djava.ext.dirs 指定的目录 | 加载 Java 扩展库(如 javax.servlet ),增强核心功能。 |
AppClassLoader | ExtClassLoader | 应用类路径:- `-classpath` 或 `-cp` 指定的路径 - 默认当前目录 (. ) | 加载用户代码和第三方依赖,是默认的类加载器(通过 ClassLoader.getSystemClassLoader() 获取)。 |
LaunchedURLClassLoader | AppClassLoader (可配置) | Spring Boot 应用类路径 + 依赖 JAR 包:``- 打包后的 BOOT-INF/classes - BOOT-INF/lib/*.jar | Spring Boot 特有,支持模块化加载和热部署,通过 spring-boot-loader 实现。 |
ClassLoader.getSystemResourceAsStream()
使用的是AppClassLoader
- 本地ok, 是因为
AppClassLoader
, 在IDEA环境时可以加载到target目录下的所有文件 - dev不行, 是因为
AppClassLoader
无法加载到springboot-fat.jar
下应用jar
中的配置文件, 应该使用Thread.currentThread().getContextClassLoader()
以切换成LaunchedURLClassLoader
加载