说实话,我们总是用人家 JDK 的内部 API,是不是有点儿欺负人。
- Java 17 更新(0):前言
- Java 17 更新(1):更快的 LTS 节奏
- Java 17 更新(2):没什么存在感的 strictfp 这回算是回光返照了
- Java 17 更新(3):随机数生成器来了一波稳稳的增强
- Java 17 更新(4):这波更新,居然利好 mac 用户
- Java 17 更新(5):历史包袱有点儿大,JDK 也在删代码啦
- Java 17 更新(6):制裁!我自己私有的 API 你们怎么随便一个人都想用?
- Java 17 更新(7):模式匹配要支持 switch 啦
- Java 17 更新(8):密封类终于转正
- Java 17 更新(9):Unsafe 不 safe,我们来一套 safe 的 API 访问堆外内存
- Java 17 更新(10):访问外部函数的新 API,JNI 要凉了?
- Java 17 更新(11):支持矢量运算,利好科学计算?
- Java 17 更新(12):支持上下文的序列化过滤器,又一次给序列化打补丁
今天我们来聊聊 JEP 403: Strongly Encapsulate JDK Internals。这一条对于使用 JDK 内部 API 的应用场景来讲会比较受影响。
JDK 的动作还是很慢的,它给开发者提供了相当长的过渡期。从 Java 9 引入模块化开始,JDK 对于其内部的 API 的访问限制就已经明确开始落地,只是当时我们可以通过配置启动参数 –illegal-access 来继续使用 JDK 的内部 API,其中 Java 9 - Java 15 这个参数默认 permit,Java 16 默认 deny。
不过,现在不可以了。在 Java 17 当中使用 –illegal-access 将会得到以下警告,并且没有任何效果:
1 | Java HotSpot(TM) 64-Bit Server VM warning: Ignoring option --illegal-access=permit; support was removed in 17.0 |
按照提案的说明,被严格限制的这些内部 API 包括:
- java.* 包下面的部分非 public 类、方法、属性,例如 Classloader 当中的 defineClass 等等。
- sun.* 下的所有类及其成员都是内部 API。
- 绝大多数 com.sun.* 、 jdk.* 、org.* 包下面的类及其成员也是内部 API。
举个例子:
1 | package com.sun.beans; |
在 java.desktop 模块下有这么一个类,非常简单,就是对 WeakHashMap 做了个包装。我想要用一下它,我该怎么办呢?
复制一份到我的工程里面。
不是,不是。。。优秀的程序员不应该 CV 代码。。。所以我直接使用它。
啊,不行。那我可以反射呀~ 我可真是个小机灵鬼。这波反射下来真是无人能敌。
1 | try { |
满怀欣喜的运行它。。。
1 | java.lang.IllegalAccessException: class com.bennyhuo.java17.ReflectionsInternal cannot access class com.sun.beans.WeakCache (in module java.desktop) because module java.desktop does not export com.sun.beans to unnamed module @776ec8df |
en???这让我想起了 Android P,你看这个字母 P,它的发音充满了挑衅,它的形状还有点儿像官方在嘲笑我们
现在 Java 17 也玩这个啊,反射都不行了啊这。。
Java 16 我们可以通过在运行时加入 --illegal-access=permit
来运行,虽然会有一堆警告:
1 | # java --illegal-access=permit com.bennyhuo.java17.ReflectionsInternal |
不过正如我们前面所说,Java 17 当中这个参数无效了:
1 | # java --illegal-access=permit com.bennyhuo.java17.ReflectionsInternal |
这就是上帝在关门的时候(Java 9),顺便也提醒我们窗户也马上要关上了,还不赶紧滚出去?然后上帝又花了三年把窗户也关上了(Java 17)。不过,它总算是还留了一个通气孔。。。
Java 17 当中 –add-opens 仍然有效,通过开启它可以让我们的程序在运行时通过反射访问指定的类:
1 | --add-opens java.desktop/com.sun.beans=ALL-UNNAMED |
所以,上面的代码想要运行,只能:
1 | # java --add-opens java.desktop/com.sun.beans=ALL-UNNAMED com.bennyhuo.java17.ReflectionsInternal |
所以这波限制是要来真的,赶快跑吧!
大家也可以参考 受影响的 API 清单 来规划自己的 JDK 升级。
顺便说一句,著名的 Unsafe 类不在这一波制裁的名单以内,可能是 Unsafe 应用太广泛了吧,而且 Java 官方也没有找到合适的替代品来满足需求,就先放着了(Unsafe 我们在后面访问堆外内存的内容中还会有介绍)。
好啦,关于加强控制内部 API 的限制的更新,我们也就介绍这么多,对大家的影响嘛,应该也不大(只要不升级)。
关于作者
霍丙乾 bennyhuo,Kotlin 布道师,Google 认证 Kotlin 开发专家(Kotlin GDE);《深入理解 Kotlin 协程》 作者(机械工业出版社,2020.6);前腾讯高级工程师,现就职于猿辅导
- GitHub:https://github.com/bennyhuo
- 博客:https://www.bennyhuo.com
- bilibili:bennyhuo不是算命的
- 微信公众号:bennyhuo