原因:
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");
方案三:折中转换
// 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);
调试:
修改后的调试:
来源:oschina
链接:https://my.oschina.net/u/2351011/blog/4284092