如果你的项目在IDE中出现了像下面这些奇怪的错误
-
object is not an instance of declaring class // 对象不是声明类的实例
-
java.lang.ClassCastException: com.example.A cannot be cast to com.example.A // A类无法转换成A类
-
又或者是全局静态变量莫名变为了null,前一秒才看到静态变量被赋值了,下一秒获取的时候就出现了空指针异常。
而且这些错误在使用 java -jar xx.jar
还不会出现,那么很有可能是因为你是用了 spring-boot-devtools
依赖
官方描述:
By default, any open project in your IDE will be loaded using the “restart” classloader, and any regular .jar file will be loaded using the “base” classloader. If you work on a multi-module project, and not each module is imported into your IDE, you may need to customize things. To do this you can create a META-INF/spring-devtools.properties file.
默认情况下,IDE中任何打开的项目都将使用 restart classloader加载,而任何常规的.jar文件都将使用 base classloader加载。如果你在一个多模块项目上工作,并且不是每个模块都被导入到你的IDE中,你可能需要自定义一些东西。要做到这一点,你可以创建一个META-INF/spring-devtools.properties文件。
原因:
- 项目中的java文件,因其可能随时被修改,为了热部署及时生效,这些java文件对于的类会使用
org.springframework.boot.devtools.restart.classloader.RestartClassLoader
类加载器进行加载。如果同时有jar中的一些代码使用了反射等技术使用我们项目的类时,就会使用AppClassLoade
进行加载。造成本该是一个类的类,因被不同的类加载器加载而同时出现两个不同的类,而出现上面的错误。
解决办法:
-
不使用
spring-boot-devtools
-
在resource下创建META-INF/spring-devtools.properties
restart.exclude.companycommonlibs=排除的jar包 restart.include.projectcommon=包含的jar包 // 使用restartClassLoader加载
下面是我解决这个问题的实际步骤
下面是我工作中遇到这个问题的解决思路。我的项目中出现了1和3这样的问题,我的项目中有一个类
AppContext
类,其中有一个全局静态变量context
-
使用 debug 断点,在 context 被赋初始值的的地方的下一行,暂停程序,使用
jmap -dump:live,format=b,file=heap-dump-1.bin pid
导出程序的堆文件,在使用jhat heap-dump.bin
分析堆文件,此时 context 不为null -
程序继续运行,再次导堆文件进行分析,这时 context 变为了 null ,同时发现 ClassLoader 发生了变化
-
基本确认是因为ClassLoader变化导致的问题,再次使用
java -jar xx.jar
运行分析,感觉 RestartClassLoader 有些特殊,然后百度搜索 restartClassLoader 解决了问题
参考资料:
本文转自 https://www.cnblogs.com/zerolinck/p/15412795.html,如有侵权,请联系删除。
标签:spring,boot,jar,devtools,IDE,restart,加载 From: https://www.cnblogs.com/1963942081zzx/p/17268665.html