最近做项目遇到一个坑,在Resources文件配置SDK初始化参数,本地运行可以读取到文件内容,但是打包部署到服务器上就会出现读不到资源文件的情况,这里记录一下。下图是资源文件放置目录:
一开始读取代码如下:
Properties properties = new Properties();
FileInputStream fileInputStream = null;
try {
String path = OnlinepayApplication.class.getClassLoader().getResource("").getPath();
fileInputStream = new FileInputStream(path + "drippay.properties");
properties.load(fileInputStream);
fileInputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
这种读取方式是从程序编译生成的target文件家目录下找资源文件,下图是编译生成的target目录:
但是呢,我们部署到服务器上之后是没有target文件夹的,所以找不到。然后经过一番查找,改用下面方式获取资源文件,代码如下:
InputStream inputStream = null;
Properties properties = new Properties();
try {
ClassPathResource resource = new ClassPathResource("drippay.properties");
inputStream = resource.getInputStream();
properties.load(inputStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
这种方式很好的解决了这个问题。虽然解决了问题,但是我们要知道为什么这种方式可以。所以我决定一探究竟。首先我们看一下ClassPathResource构建方法:
public ClassPathResource(String path) {
this(path, (ClassLoader)null);
}
public ClassPathResource(String path, ClassLoader classLoader) {
Assert.notNull(path, "Path must not be null");
String pathToUse = StringUtils.cleanPath(path);
if (pathToUse.startsWith("/")) {
pathToUse = pathToUse.substring(1);
}
this.path = pathToUse;
this.classLoader = classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader();
}
我们发现实际调用的是ClassUtils.getDefaultClassLoader(),进入getDefaultClassLoader()方法:
public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
} catch (Throwable var3) {
}
if (cl == null) {
cl = ClassUtils.class.getClassLoader();
if (cl == null) {
try {
cl = ClassLoader.getSystemClassLoader();
} catch (Throwable var2) {
}
}
}
return cl;
}
关键代码Thread.currentThread().getContextClassLoader(),得到当前线程类加载器,从而获取到了我们的资源文件,这也说明了OnlinepayApplication.class.getClassLoader()和Thread.currentThread().getContextClassLoader()的区别(两者类加载器不一致),所以代码中动态加载jar、资源文件的时候,首先应该是使用Thread.currentThread().getContextClassLoader()。
以上所述,如有不正之处,请不吝赐教!