Java 踩坑之资源文件读取

在Spring Boot项目中,开发者遇到资源文件读取问题,本地运行正常,部署到服务器则无法找到资源。通过分析,发现原始代码从target目录读取,而服务器上不存在该目录。解决方案是使用ClassPathResource结合线程上下文类加载器来正确读取资源文件,深入理解ClassPathResource和类加载器的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       最近做项目遇到一个坑,在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()

 

以上所述,如有不正之处,请不吝赐教!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值