springBoot Devtools 与 mybatis 集成后,发现selectByPrimaryKey返回实现类不能顺利转换,报java.lang.ClassCastException异常

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_31803503/article/details/83857348

1.遇到的问题

@Override
    public User findUserById(Integer userId) throws Exception {
        Object obj = this.userMapper.selectByPrimaryKey(userId);
        System.out.println(obj.getClass().getName());
        System.out.println("selectByPrimaryKey.obj.classLoader:"+obj.getClass().getClassLoader());
        System.out.println("User.class.classLoader:"+User.class.getClassLoader());
        User user = (User) obj;
        return null;
    }

问题就是当我使用tk.mybatis插件根据userId查询对象时,查询回来后数据不能转换成User。其中user配置与userMapper均为正确

2.分析

那么为什么会出现转换不成功,在这之前我自己也测试通过,但是自添加springboot热部署插件Devtools 就出现这个问题,会不会与Devtools 的添加有关了,然后查阅Devtools 相关信息

这里贴上devtools原理

devtools:是boot的一个热部署工具,当我们修改了classpath下的文件(包括类文件、属性文件、页面等)时,会重新启动应用(由于其采用的双类加载器机制,这个启动会非常快,如果发现这个启动比较慢,可以选择使用jrebel)

  • 双类加载器机制:boot使用了两个类加载器来实现重启(restart)机制:base类加载器(简称bc)+restart类加载器(简称rc)
    • bc:用于加载不会改变的jar(eg.第三方依赖的jar)
    • rc:用于加载我们正在开发的jar(eg.整个项目里我们自己编写的类)。当应用重启后,原先的rc被丢掉、重新new一个rc来加载这些修改过的东西,而bc却不需要动一下。这就是devtools重启速度快的原因。

双类加载器机制?这不就是用两个classLoader去加载同一个项目的代码吗?这个机制会不会与 双亲委派模型 吗?

然后我打印出各自的classLoader发现确实不一样:

com.sendbp.user.model.User
selectByPrimaryKey.obj.classLoader:sun.misc.Launcher$AppClassLoader@18b4aac2
User.class.classLoader:org.springframework.boot.devtools.restart.classloader.RestartClassLoader@7237dc28

一个是:sun.misc.Launcher$AppClassLoader@18b4aac2

一个是:org.springframework.boot.devtools.restart.classloader.RestartClassLoader@7237dc28

类加载器资料可以参考:

深入理解Java虚拟机

https://blog.csdn.net/qq_36642340/article/details/81506435

3.解决方法

在使用 DevTools 时,通用Mapper经常会出现 class x.x.A cannot be cast to x.x.A。

同一个类如果使用了不同的类加载器,就会产生这样的错误,所以解决方案就是让通用Mapper和实体类使用相同的类加载器即可。

DevTools 默认会对 IDE 中引入的所有项目使用 restart 类加载器,对于引入的 jar 包使用 base 类加载器,因此只要保证通用Mapper的jar包使用 restart 类加载器即可。

在 src/main/resources 中创建 META-INF 目录,在此目录下添加 spring-devtools.properties 配置,内容如下:

restart.include.mapper=/mapper-[\\w-\\.]+jar
restart.include.pagehelper=/pagehelper-[\\w-\\.]+jar
使用这个配置后,就会使用 restart 类加载加载 include 进去的 jar 包。

可以参考:

https://blog.csdn.net/isea533/article/details/70495714

感兴趣的朋友可以关注微信公众号(会定时推送新的知识):

猜你喜欢

转载自blog.csdn.net/qq_31803503/article/details/83857348