Skip to content

devtools

isea533 edited this page Apr 26, 2018 · 2 revisions

Spring Boot Devtools 兼容性分析

最早在 Spring Boot 中使用 Devtools 时,使用通用 Mapper 会报错: can't cast x.y.Z to x.y.Z , 包名和类名完全一样,为什么会出现这个错误呢?

最早有人通过 issue 提出了一个解决方案,就是增加下面这个配置(spring-devtools.properties):

restart.include.mapper=/mapper-[\\w-\\.]+jar

在一段时间内,这个配置解决了前面遇到的问题,但是 4.0 版本发布后,又发现有人遇到了类似问题。

后来发现 core 下面并没有 spring-devtools.properties 配置文件,我还以为缺了,还在 4.0.2 中增加了这个, 实际上这个文件一直都没少,在 spring 子模块中一直都有这个文件,而且放在 spring 子模块也是最合适的位置。

为什么一直都有这个配置,还会出错呢?

实际上在后来发生的下面两个症状很可能都是 Devtools 导致的:

  • Error invoking SqlProvider method (tk.mybatis.mapper.provider.SpecialProvider.dynamicSQL)
  • java.lang.NoSuchMethodException: tk.mybatis.mapper.provider.SpecialProvider.<init>()

在 faq 中专门介绍了这两个错误的解决办法,但是一直没有完全处理所有的情况。

并且由于 Devtools 导致通用 Mapper 无法正常启动,因此也很难出现 can't cast x.y.Z to x.y.Z

为什么会出现 can't cast x.y.Z to x.y.Z

详细分析看这里:https://github.com/abel533/mapper-cast-exception

为什么前期增加 spring-devtools.properties 后解决了这个问题?

没有增加时,因为 IDE 运行时,通用 Mapper 的 mapper-x.x.x.jar 会被 AppClassLoader 加载, 因此会出现 can't cast x.y.Z to x.y.Z

当增加上面的配置后,mapper-x.x.x.jar 会被 RestartClassLoader 加载,此时他们就一致了, 表面上解决了这个问题。

为什么后来会导致通用 Mapper 无法初始化?

就是因为这个配置导致的。

前面使用时,有可能你所有的 XXMapper 都在当前的 IDE 中,因此这些 XXMapper 都会使用 RestartClassLoader 加载。

但是如果你依赖的项目(包含 XXMapper)不在当前的 IDE 中,那么该 XXMapper 就会使用 AppClassLoader 加载。

因此就会出现 AppClassLoader 加载的 XXMapper 获取 RestartClassLoader 加载的 @RegisterMapper 注解时, 就会找不到,因此该 XXMapper 就无法初始化,调用 XXMapper 的方法时就会报下面的错:

  • Error invoking SqlProvider method (tk.mybatis.mapper.provider.SpecialProvider.dynamicSQL)

同样 XXMapper 对应 XX 使用 Example(XX.class) 时,就报错找不到 XX 对应的表名。

合理的情况

最合理的情况就是没有 spring-devtools.properties 配置文件。