记一次Spring boot本地启动报IllegalAccessError异常原因

序言

最近项目接入公司一个 SSO 统一身份认证组件,这里简单说明一下:

组件提供的自动配置类启动时如果 UserCenterActivated 这个Bean不存在的话会使用组件默认的用户激活组件,然后我是在项目中实现了自己的一个用户激活类并继承了UserCenterActivated抽象类。

image-20240105162049473

项目启动时奇怪的出现了以下错误:

1
class xxx.sso.support.$Proxy130 cannot access its superinterface xxx.sso.support.AppRegistryInfo

并且该情况只在本地出现,打包部署到服务器并未出现问题。

所以我判断肯能与本地的maven插件有关,因为有些maven插件只有在开发中生效。

最终定位到是由于spring-boot-devtools这个插件导致的。

热部署插件

介绍

spring-boot-devtools插件支持在spring-boot开发中对项目修改的代码进行快速部署,而无需重启JVM的一款工具。

使用spring-boot-devtools,可以实现指定目录(默认为classpath路径)下的文件进行更改后,项目自动重启,更改后的代码自动生效。

原理

根据官方的定义:spring-boot-devtools使用了两个类加载器ClassLoader,一个ClassLoader加载不会发生更改的类(第三方jar包)一般是应用类加载器,我们暂且叫他 base ClassLoader,另一个ClassLoaderrestart ClassLoader)加载会更改的类(自定义的类)。

默认情况下,IDE 中的任何打开项目都使用restart类加载器加载,而普通的jar 文件则使用base类加载器加载。如果使用 mvn spring-boot:rungradle bootRun,情况也是如此: 包含 @SpringBootApplication 的项目使用restart类加载器加载,其他所有内容使用base类加载器加载。

image-20240105173751969

这就导致我项目中的代码都是由restart ClassLoader加载器加载的,而我引入的组件jar包是由app ClassLoader加载的,这就可能会导致一些类加载问题,特别是在多模块项目中。

SSO组件在第三方jar包中,这将导致DevTools的重新启动类加载器出现问题。代理对象是由restart类加载器加载的,但被代理对象本身是由应用类加载器加载,因此会导致IllegalAccessError

解决方案

  • 大力出奇迹,删掉或者注释掉spring-boot-devtools插件。
  • META-INF/spring-devtools.properties中设置restart.include.projectcommon=被代理对象所在的jar,保证代理对象和被代理对象使用同一个类加载器。

参考


记一次Spring boot本地启动报IllegalAccessError异常原因
https://seeyourface.cn/2024/01/05/记一次Spring boot本地启动报IllegalAccessError异常原因/
作者
Yang Lei
发布于
2024年1月5日
许可协议