Classloader与Thread.currentThread().getContextClassLoader()区别

匆匆九月,回到目前的创业公司工作已满二个多月了。回来后每天都有干不完的任务,对于每天的工作每天也很少有时间来进行总结与思考。仿佛让我想到了两年前刚来这家公司时的样子,虽然一直很忙有事干,但有一种瞎忙的感觉,每天看似很充实,但回过头来看其实是很空的,很有一种打酱油的感觉,这样长此以往下去个人感觉对于自己的职业生涯并不是什么好事。时间真的好快,明天又是国庆了,这个月还没有记录过任何文章,今天紧紧抓住2018年9月的尾巴赶紧写一篇吧!

问题描述

这周工作上遇到一个需要在JAVA项目里调用其他语言代码的需求,为了代码管理方便,我将其他语言的代码放在了项目的resource目录下,并在IDEA调试时成功通过了,直接用的ClassLoader.getSystemResource方法来实现的,待整体项目开发完毕后,将整个项目打为了fat jar,在jar里运行确报错了,报的找不到文件的异常。看到这个异常,很快锁定了报错的原因,尽管很简单,但感觉还是很有必要再次记录一下。其报错原因和去年记录的一篇文章是一样的情况(java加载jar包下的资源文件过程及原理分析https://blog.csdn.net/puhaiyang/article/details/77409203

为了确认,临时写了下如代码以验证

@RestController
@RequestMapping(value = "getResource")
public class GetResourceController {

    @GetMapping(value = "get")
    public ResponseEntity<String> getResource() {
        String resourcePath = "lisp/helloworld.lisp";
        URL systemResource = ClassLoader.getSystemResource(resourcePath);
        System.out.println(">>>" + systemResource);
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(">>>>>" + systemClassLoader.toString());
        System.out.println(">>>" + systemClassLoader.getResource(resourcePath));
        ClassLoader cuurentThreadClassLoader = Thread.currentThread().getContextClassLoader();
        System.out.println(">>>>>" + cuurentThreadClassLoader.toString());
        System.out.println(">>>" + cuurentThreadClassLoader.getResource(resourcePath));
        ClassLoader parentClassLoader = cuurentThreadClassLoader.getParent();
        System.out.println("parent:" + parentClassLoader);
        ClassLoader thisClassLoader = GetResourceController.class.getClassLoader();
        System.out.println("this:" + thisClassLoader);
        return new ResponseEntity<String>("ok", HttpStatus.OK);
    }


}

运行后日志如下:

即:

>>>file:/E:/idea_space/spring_hello/test-pro/target/classes/lisp/helloworld.lisp
>>>>>sun.misc.Launcher$AppClassLoader@18b4aac2
>>>file:/E:/idea_space/spring_hello/test-pro/target/classes/lisp/helloworld.lisp
>>>>>TomcatEmbeddedWebappClassLoader
  context: ROOT
  delegate: true
----------> Parent Classloader:
sun.misc.Launcher$AppClassLoader@18b4aac2

>>>file:/E:/idea_space/spring_hello/test-pro/target/classes/lisp/helloworld.lisp
parent:sun.misc.Launcher$AppClassLoader@18b4aac2
this:sun.misc.Launcher$AppClassLoader@18b4aac2

而通过fat jar运行结果如下:

那么是什么原因导致在springboot的fat jar里运行时通过Classloader就拿不到项目中的资源文件呢?通过打印的日志可以看出,是由于classloader的不同导致的,在IDEA开发工具中运行时直接调用classloader调用的是AppClassLoader,在IDEA环境时可以加载到target目录下的所有文件。而如果在springBoot项目的fat jar方式运行时仍然还是用AppClassLoader去加载项目内的静态资源的话就会找不到的,因为springBoot加载静态资源文件是用的内置tomcat的classloader去加载的,即上图中的LaunchedURLClassLoader,所以在fat jar加载时就需要用这个classLoader去加载项目中的资源文件了。

总结:

为了避免在项目中加载不到本项目中静态资源文件的BUG发生,调用静态资源的classLoader最好用Thread.currentThread().getContextClassLoader()方法来获取,因为一般同一个项目中java代码和其静态资源文件都是同一个classLoader来加载的,以此确保通过此classLoader也能加载到本项目中的资源文件。

国庆快乐!

 

  • 25
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水中加点糖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值