Spring Boot MyBatis 使用 Redis 做为二级缓存遇到的问题

在 Spring Boot MyBatis使用 Redis 做为二级缓存的时候,遇到了一个使人诡异的问题,在 MyBatis 从 Redis 中取出缓存并反序列的时候老是报这个错误java

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.ClassCastException: hello.entity.User cannot be cast to hello.entity.User
java.lang.ClassCastException: hello.entity.User cannot be cast to hello.entity.User
....

根据异常能够看出是类型不匹配的异常,可是一样的类名,一样的字段,怎么就不匹配了呢?web

我首先 MyBatis Redis cache 库是否是有BUG,已经它一直带着个 beta 的字眼,并且已经4年没更新了redis

<dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-redis</artifactId>
            <version>1.0.0-beta2</version>
        </dependency>

可是我换成 MyBatis Memcache cache 用 Memcached 作二级缓存也是一样的问题,感受应该不是 MyBatis 的问题了,spring

而后我转换思路搜索 Spring Boot ClassCastException 终于找到了问题所在,原来是 spring-boot-devtools 的锅缓存

https://stackoverflow.com/questions/37977166/java-lang-classcastexception-dtoobject-cannot-be-cast-to-dtoobjectmybatis

When you use DevTools with caching, you need to be aware of this limitation.架构

When the object is serialized into the cache, the application class loader is C1. Then after you change some code/configuration, devtools automatically restart the context and creates a new classloader (C2). When you hit that cache method, the cache abstraction finds an entry in the cache and it deserializes it from the store. If the cache library doesn't take the context classloader into account, that object will have the wrong classloader attached to it (which explains that weird exception A cannot be cast to A).app

TL;DR do not serialize classes with devtools if the cache library doesn't use the context classloader. Or put your cache library in the application classloader:spring-boot

干掉 spring-boot-devtools 终于搞定了this

更多架构、PHP、GO相关踩坑实践技巧请关注个人公众号

相关文章
相关标签/搜索