springboot 热部署导致类型转换异常

夙愿已清 提交于 2020-08-09 15:53:54

原因:

1.  JVM判断两个类对象是否相同的依据:一是类全称;一个是类加载器.(具体原理请自行百度,在此不再赘述)。

2. 大家都知道虚拟机的默认类加载机制是通过双亲委派实现的。springboot为了实现程序动态性(比如:代码热替换、模块热部署等,白话讲就是类文件修改后容器不重启),“破坏或牺牲” 了双亲委派模型。springboot通过强行干预-- “截获”了用户自定义类的加载(由jvm的加载器AppClassLoader变为springboot自定义的加载器RestartClassLoader,一旦发现类路径下有文件的修改,springboot中的spring-boot-devtools模块会立马丢弃原来的类文件及类加载器,重新生成新的类加载器来加载新的类文件,从而实现热部署。比较流行的OSGI也能实现热部署)。

3、当对象被序列化到缓存里时,当前应用的类加载器是C1,当你改变了一些代码或者配置文件的时候,DevTools 工具将会自动重新启动这个容器,并且创建一个新的类加载器 C2. 这时候调用这个具有缓存的方法时,缓存管理将会从缓存里找到该条缓存记录并进行反序列化操作。如果缓存库不考虑上下文的话,也就是没注意到类加载器的变化时,该对象将会有错误的类加载器。即:类加载器不一致所导致。

方案一、解决方案就是在resources目录下面创建META-INF文件夹,然后创建spring-devtools.properties文件,文件加上类似下面的配置:

restart.include.shiro=/shiro-[\\w-\\.]+jar
restart.include.thymeleaf.extras.shiro=/thymeleaf-extras-shiro-[\\w-\\.]+jar
restart.include.sharksucker=/sharksucker-[\\w-\\.]+jar

方案二、不使用spring-boot-devtools

(1)、删除pom中 的依赖

(2)、保留pom中 的依赖,在启动类里增加 

System.setProperty("spring.devtools.restart.enabled", "false");
也可以在application.设置禁用属性,但它的作用域只发生在当前模块,如果你的项目牵扯到多个模块,最好通过上面的方式在整个运行系统的级别禁用,以免出现多个模块之间实现类文件调用时类加载器不一致的问题。

方案三:折中转换

// SysUser user = (SysUser) subject.getPrincipal(); //spring-boot-devtools 引起转换问题//代码转换实体类Object obj = subject.getPrincipal();
SysUser user =null;if(obj instanceof SysUser) {
    user = (SysUser) obj;
} else {
    user = JSON.parseObject(JSON.toJSON(obj).toString(), SysUser.class);    
}
String username = user.getNickname();

方案四:克隆

如果需要热部署,对于这种强转异常改为克隆的方式即可。
BeanUtils.copyBeanProp(session, obj);

 

调试:

修改后的调试:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!