关于springboot项目的系统类加载器和java默认类加载器的关系和区别

最近在搞一个动态加载外部jar包,进行动态加载和调用的项目,外部包的类加载用继承于URLClassLoader类加载器的一个自定义类加载器,为的是打破原始的双亲委派机制。

项目内部类就用项目自己的默认类加载器,最开始用的是ClassLoader.getSystemClassLoader()即AppClassLoader。ok,然后再IDE用启用测试,一切正常,内部类用AppClassLoader加载,外部类用自定义类加载器加载都成功了。

结果发布到测试环境,测试时发现一堆java.lang.NoClassDefFoundError,分析ClassLoader源码良久,没有头绪,因为本地IDE各种加载都是好的,上了测试环境就各种类加载失败。

于是决定maven打包,然后使用java -jar的方式在本地试下。结果发现,也报NoClassDefFoundError。那就是打包启动方面应该存在差异。通过日志分析出是系统默认加载器 加载内部类时NoClassDefFoundError,于是尝试使用当前类的类加载器即 xxx.class.getClassloader,并打印。发现java -jar方式启动,此处打印的系统默认加载器是springboot的LaunchedURLClassLoader,而不是APPClassLoader。问题就出在这里,经优化当前系统类加载器用Thread.currentThread().getContextClassLoader()来加载内部类,问题就解决了。

Java -Jar 和IDE里启动Sprintboot 有什么区别

Java -Jar是以FAT JAR的方式用LaunchedURLClassLoader来load class。而在IDE中则是直接以ApplicationClassLoader来load的。这种差别会导致调用classloader.getResourceAsStream()得到不一样的结果,这是因为FAT JAR启动时,LaunchedURLClassLoader的load的urls并没有FAT JAR本身,如abc-0.0.1-SNAPSHOT.jar, 但是应用中的src/main/resources/META-INF/resources目录被打包到了FAT JAR里,也就是abc-0.0.1-SNAPSHOT.jar!/META-INF/resources,这样这些resource也就不会被访问到了

这里参考了一位大神的文章,非常有用,聊一聊Springboot的类加载机制 - 简书

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值