SpringBoot从Redis中取对象缓存强转发生ClassCastException

SpringBoot从Redis缓存中取对象强转发生ClassCastException

今天在优化单点登录代码时,将登录用户存进Redis,并在登录拦截器根据Token取出来时,发现Object转换居然报了强转异常?这让我有点措手不及,从来没有遇到过这种情况

异常日志信息

java.lang.ClassCastException: com.model.user.entity.UserEntity cannot be cast to com.model.user.entity.UserEntity at com.zlhj.re.common.config.web.interceptor.LoginAuthInterceptor.preHandle(LoginAuthInterceptor.java:77) at org.springframework.web.servlet.HandlerExecutionChain.applyPreHandle(HandlerExecutionChain.java:136) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1034) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897) at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
仔细看可以发现两边转换的包名和类名是完全一样的,【java.lang.ClassCastException: com.model.user.entity.UserEntity cannot be cast to com.model.user.entity.UserEntity】
这说明两者确实是同一个类。但是为什么还会出现强转异常

代码片段

在这里插入图片描述
从上面图片可以看到我将对象从Redis中取出来时,类的类型已经是UserEntity类型了

报错原因

从StackOverFlow中找到了一篇文章:ArticleOfStackOverFlow, 发现确实是这样,因为项目中用到了SpringBoot热部署devtools的依赖包
在这里插入图片描述
我们先来了解一下spring-boot-devtools是个什么东西吧:

spring-boot-devtools是spring为开发者提供的一个服务模块,用来使Spring Boot应用支持热部署,也就是修改代码后自动启动springboot服务,无需手动重启Spring Boot应用,以提高开发者的开发效率

那么它的实现原理:

主要是使用了两个ClassLoader,一个Classloader加载不会改变的类(第三方Jar包),另一个ClassLoader加载会更改的类,称为 restart ClassLoader,这样在有代码更改的时候,原来的restartClassLoader 被丢弃,重新创建一个restartClassLoader,由于需要加载的类相比较少,所以实现了较快的重启时间(5秒以内)。

由此我们可以知道,使用了两个ClassLoader,两个不同的类加载器,举个栗子: 当对象序列化到缓存中时,应用程序类加载器是C1。然后,更改一些代码或者配置后,devtools会自动重新启动上下文并创建一个新的类加载器C2。所以当你通过redis操作获取缓存反序列化的时候应用的类加载器是C2,虽然包名及其来类名完全一致,但是序列化与反序列化是通过不同的类加载器加载则在JVM中它们也不是同一个类。如果缓存库没有考虑上下文类加载器,那么这个对象会附加错误的类加载器 ,也就是我们常见的类强制转换异常(ClassCastException)
所以出现强制转换异常的原因是使用的类加载器不一样。
报错的同学请自己查看一下POM文件是否有引用这一依赖吧

解决方法

解决方法就是将这个依赖注释掉,不使用这一工具。我原本是用的一个叫Dozer的转换工具来转换的,原本觉得因为一个报错而去放弃使用一个工具有点激进。但是同事说以后肯定不止这一个地方要从Redis中取对象,难道每个地方你都得用工具转一下吗?我想了下确实有道理,热部署其实是属于一个可有可无的功能,但是因为这个功能让我们代码重复量更大就有点不值得了。所以还是果断抛弃这工具把它注释了

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 关于Spring Boot中的Redis注解可以用来缓存方法的问题,我可以回答。 Spring Boot中的@Cacheable注解可以使用Redis作为缓存存储,它可以用于将一个方法的返回值缓存起来,下次调用该方法时,如果缓存中存在相同的参数,就直接从缓存中获取结果,而不是再次执行该方法。可以通过指定缓存的key和过期时间等参数来控制缓存的行为。 例如,使用@Cacheable注解可以这样定义一个缓存方法: ``` @Cacheable(value="myCache", key="#param") public Object cachedMethod(String param) { // 方法的实现代码 } ``` 这段代码会将方法的返回值存储到名为"myCache"的缓存中,缓存的key是传入的参数param的值。如果下次再次调用该方法,如果参数值相同,就直接从缓存中获取结果。 需要注意的是,使用Redis作为缓存存储时,需要在Spring Boot中配置Redis的连接信息和相关的依赖库。同时,@Cacheable注解也需要和其他相关注解一起使用,例如@CacheConfig注解,用于配置缓存的一些属性,例如缓存名称和缓存的key前缀等。 总之,Spring Boot中的Redis注解可以用来方便地实现方法级别的缓存,可以提高系统的性能和响应速度。 ### 回答2: Spring Boot中通过注解@Cacheable来实现对方法的缓存。@Cacheable注解可用于类和方法上,用于标记需要进行缓存的方法。 通过在方法上添加@Cacheable注解,当方法被调用时,Spring Boot首先会检查缓存中是否存在该方法的结果,如果存在,则直接从缓存中获取结果并返回,而不会执行真正的方法体;如果不存在,则执行方法体,并将方法的返回结果放入缓存中。下次调用该方法时,直接从缓存中获取结果。 @Cacheable注解可以通过设置value属性来指定使用哪一个缓存策略。例如,@Cacheable(value="userCache")表示使用名为userCache的缓存策略进行缓存。 @Cacheable注解还可以通过设置key属性来指定缓存的key值。key属性的默认值是方法的所有参数组成的唯一值。通过指定不同的key值,可以实现对不同参数组合的缓存。 在使用@Cacheable注解时,需要先在配置文件中配置对应的缓存策略。例如,可以通过在application.properties或application.yml文件中添加配置spring.cache.type=redis来使用Redis作为缓存策略。 总之,Spring Boot的@Cacheable注解可以通过对方法添加缓存逻辑,减少方法的执行次数,提高应用的性能。这是通过将方法的结果缓存起来,提供快速的访问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值