浅谈MyBatis-Plus 提示发生了非法的反射访问操作

 更新时间:2026年01月25日 14:34:28   作者:一线大码  
本文主要介绍了MyBatis-Plus 提示发生了非法的反射访问操作,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

最近使用 MyBatis-Plus 框架,在执行 SQL 查询的时候控制台日志提示了该警告信息(An illegal reflective access operation has occurred),并且只有首次执行的时候才提示,同样的方法再次调用则不会提示,我用的 JDK11。下面转载一篇文章,解决了这个问题。

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.baomidou.mybatisplus.core.toolkit.SetAccessibleAction (file:/C:/Users/wangbo.GTCOM/.m2/repository/com/baomidou/mybatis-plus-core/3.4.3.4/mybatis-plus-core-3.4.3.4.jar) to field java.lang.invoke.SerializedLambda.capturingClass
WARNING: Please consider reporting this to the maintainers of com.baomidou.mybatisplus.core.toolkit.SetAccessibleAction
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

反射是一项相当强大的特性,不仅在各类框架中被广泛应用,即使是在日常开发中我们也隔三差五得要和它打交道。然而在 JDK9 中 JDK 对反射加上了一些限制,需要注意。

考虑有如下的代码:

import java.lang.reflect.Field;
import java.util.ArrayList;

public class TestReflect {

    public static int getCapacity(ArrayList<?> l) throws Exception {
        Field dataField = l.getClass().getDeclaredField("elementData");
        // 即使设置了可访问也会触发警告
        dataField.setAccessible(true);
        // 注意这行
        return ((Object[]) dataField.get(l)).length;
    }

    public static void main(String[] args) {
        var arr = new ArrayList<Integer>(4);
        try {
            System.out.println("capacity:" + TestReflect.getCapacity(arr));        
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

这段代码的作用是读取 ArrayList 的实际容量,由于 JDK 并没有为我们提供类似 cap() 这样的公开接口,所以我们不得不使用反射来绕过限制。

在 JDK8 上这段代码运行良好,然而当我们升级成 JDK9 后却会是这样的一幅画面:

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by TestReflect (file:/tmp/TestReflect.java) to field java.util.ArrayList.elementData
WARNING: Please consider reporting this to the maintainers of TestReflect
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
capacity:4

别紧张,代码还是正常运行了。其实这是 JDK9 中添加的新特性,即 reflect 不再可以访问 non-public 成员以及不可公开访问的 class,原先这些访问控制虽然存在但是可以通过 reflect 绕过,从 JDK9 开始反射也将遵循访问控制的规则。JDK9 中对于第一次访问非公开成员的操作会显示警告信息,我们可以通过使用--illegal-access=warn选项进一步显示出有用的 warning 提示:

$ java --illegal-access=warn TestReflect.java

WARNING: Illegal reflective access by TestReflect (file:/tmp/TestReflect.java) to field java.util.ArrayList.elementData
capacity:4

将 warn 替换为 debug 可以指出非法访问发生在哪一行(通过观察打印的调用堆栈),而替换为 deny 则将会直接抛出java.lang.reflect.InaccessibleObjectException异常:

$ java --illegal-access=deny TestReflect.java

java.lang.reflect.InaccessibleObjectException: Unable to make field transient java.lang.Object[] java.util.ArrayList.elementData accessible: module java.base does not "opens java.util" to unnamed module @72967906
        at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:349)
        at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:289)
        at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:174)
        at java.base/java.lang.reflect.Field.setAccessible(Field.java:168)
        at TestReflect.getCapacity(TestReflect.java:7)
        at TestReflect.main(TestReflect.java:14)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:564)
        at jdk.compiler/com.sun.tools.javac.launcher.Main.execute(Main.java:415)
        at jdk.compiler/com.sun.tools.javac.launcher.Main.run(Main.java:192)
        at jdk.compiler/com.sun.tools.javac.launcher.Main.main(Main.java:132)

对于后续的更新版本,JDK 会将 deny 作为默认的行为,不过目前(14.0.2)默认行为依旧为 permit(显示那些默认的 warning 信息)。

显而易见,新特性会导致如下的结果:

  1. 无法再通过反射修改/访问其他类型的私有成员;
  2. 无法再通过反射使用 internal APIs。

然而健康的代码并不应该依赖于非法的访问:

  1. 标记为非公开的成员本身就不希望被外部直接访问,访问应该通过 public APIs 进行;
  2. 无视访问控制会导致数据的修改变得不可控,从而产生意想不到的缺陷;
  3. 私有成员可能会随着开发 / 更新 / 修复 / 重构等活动而改变,过度依赖于访问其他 class 的私有成员会产生高耦合性的代码,使维护的负担成倍增加。

当然,想要消除警告也很容易,虽然官方文档中不建议无视或消除这个警告:

$ java --add-opens java.base/java.util=ALL-UNNAMED TestReflect.java

capacity:4

--add-opens选项将特定的 module 下的 package 公开给指定的 package,或者使用特殊值 ALL-UNAMED 代指所有匿名包(比如本例中的类),公开后我们就可以通过 reflect 来访问被公开包中 class 的成员而不抛出异常了(需要使用 setAccessible(true))。

这种 trick 实际上严重破坏了代码的封装,个人是极不推荐的;此外还可以选择将 JDK 版本锁定在 8,当然这也是不得以才为之的办法,那么对于即想尝试新版本又不想被警告信息烦扰的话该怎么办呢,只能尝试下面几种办法了:

  1. 如果是第三方依赖导致的警告,升级对应的依赖或是联系该依赖的维护人员,请他们尽快修复问题。通常来说这类向后兼容的问题修复无需花费很多的时间。
  2. 如果是自己的代码,则考虑是否要对私有成员提供可访问的 public API,是否将私有成员公有化。
  3. 如果使用了某些 internal apis,那么你的代码应该重构以避免过度依赖这些 api。

到此这篇关于浅谈MyBatis-Plus 提示发生了非法的反射访问操作的文章就介绍到这了,更多相关MyBatis-Plus 非法的反射访问内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java微服务无损发布生产实战案例及验证

    Java微服务无损发布生产实战案例及验证

    微服务架构是一项在云中部署应用和服务的新技术,这篇文章主要介绍了Java微服务无损发布生产实战及验证的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-10-10
  • SpringSecurity表单配置之登录成功及页面跳转原理解析

    SpringSecurity表单配置之登录成功及页面跳转原理解析

    这篇文章主要介绍了SpringSecurity表单配置之登录成功及页面跳转原理解析,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2023-12-12
  • 基于Java字符编码的使用详解

    基于Java字符编码的使用详解

    本篇文章对Java字符编码的使用进行了详细的分析介绍。需要的朋友参考下
    2013-05-05
  • datax-web在windows环境idea中模块化打包部署操作步骤

    datax-web在windows环境idea中模块化打包部署操作步骤

    这篇文章主要介绍了datax-web在windows环境idea中模块化打包部署操作步骤,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-05-05
  • intellij idea使用git stash暂存一次提交的操作

    intellij idea使用git stash暂存一次提交的操作

    这篇文章主要介绍了intellij idea使用git stash暂存一次提交的操作,具有很好的参考价值希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • 详解Java中ArrayList类

    详解Java中ArrayList类

    这篇文章主要介绍了Java中ArrayList类,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • spring中@ControllerAdvice 注解的使用

    spring中@ControllerAdvice 注解的使用

    @ControllerAdvice注解是Spring3.2中新增的注解,主要用于Controller的全局配置,本文就来介绍一下spring中@ControllerAdvice 注解的使用,感兴趣的可以了解一下
    2024-09-09
  • Spring MVC URL地址映射的示例代码

    Spring MVC URL地址映射的示例代码

    @RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。,这篇文章主要介绍了Spring MVC URL地址映射,需要的朋友可以参考下
    2022-07-07
  • Java一键获取(CPU、内存、硬盘、操作系统)系统信息

    Java一键获取(CPU、内存、硬盘、操作系统)系统信息

    这篇文章主要为大家详细介绍了如何使用Java一键获取CPU、内存、硬盘、操作系统等系统信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下
    2026-03-03
  • Java使用java -jar启动并按日分包日志的最佳实践

    Java使用java -jar启动并按日分包日志的最佳实践

    在生产环境中,Java应用程序通常以java -jar方式运行,而日志管理是运维的重要部分,如果日志文件过大,不仅影响性能,还会增加排查问题的难度,因此,按日分包日志成为常见的需求,本文将介绍4种实现方式,并提供详细配置和代码示例,需要的朋友可以参考下
    2025-07-07

最新评论