问题:
从Redis中取出的缓存对象,出现同一类型转换错误
最近在写Springboot项目,用到Redis缓存对象User,通过key取出来后的value并赋值给同一类型的对象,但是却出现了一个神奇的报错,同一对象无法转换为同一对象的报错,这个问题我还是第一次见,刚开始真的百思不得其解
java.lang.ClassCastException: com.blog.bean.User cannot be cast to com.blog.bean.User
解决:
开始试着找错误,在test上看能不能打印取出的缓存对象信息,开始是直接用Object类接收,打印信息完全一致,是我想要的东西;后面转换为实体类的类型User,神奇的是在springboot上的测试类上却能运行成功,没有报错,类型能成功转换,真的是伤脑筋。
最后无奈开启百度大法
终于解决:
把springboot热部署DevTools工具去掉
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-devtools</artifactId>-->
<!--<optional>true</optional>-->
<!--</dependency>-->
原因:
当User对象被序列化并存到Redis缓存里时,使用的类加载器是C1,而在此之后你改变了一些代码或者配置文件的时候,DevTools工具将会自动重新启动这个容器,并且创建一个新的类加载器 C2,这时前后两次加载User类的类加载器就不同了,两个不同类加载器加载的两个对象,JVM会认为这是两个不同的对象。
也就是Springboot为了实现代码热部署破坏了双亲委派模型,导致(User类)的类加载器由AppClassLoader变了Springboot的自定义加载器RestartClassLoader。
只有类全称相同且类加载器相同,JVM才认为类是相同的,你两次生成的对象调用不同的类加载器,虽然是同一类型的对象,但是JVM就会认为这是两个不同的对象,因此也就无法完成类型的转换。