3

Java 17 更新(6):制裁!我自己私有的 API 你们怎么随便一个人都想用?

 2 years ago
source link: https://www.bennyhuo.com/2021/10/02/Java17-Updates-06-internals/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Java 17 更新(6):制裁!我自己私有的 API 你们怎么随便一个人都想用?

发表于 2021-10-02 | 阅读次数: 1
本文字数: 5.6k | 阅读时长 ≈ 9 分钟

说实话,我们总是用人家 JDK 的内部 API,是不是有点儿欺负人。

今天我们来聊聊 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。

0B223765.jpg

不过,现在不可以了。在 Java 17 当中使用 –illegal-access 将会得到以下警告,并且没有任何效果:

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。

举个例子:

package com.sun.beans;

...
public final class WeakCache<K, V> {
private final Map<K, Reference<V>> map = new WeakHashMap<K, Reference<V>>();

public V get(K key) { ... }

public void put(K key, V value) { ... }
...
}

在 java.desktop 模块下有这么一个类,非常简单,就是对 WeakHashMap 做了个包装。我想要用一下它,我该怎么办呢?

复制一份到我的工程里面。

738DD603.png

不是,不是。。。优秀的程序员不应该 CV 代码。。。所以我直接使用它。

image-20210921083515465.png

啊,不行。那我可以反射呀~ 我可真是个小机灵鬼。这波反射下来真是无人能敌。

try {
var weakCacheClass = Class.forName("com.sun.beans.WeakCache");
var weakCache = weakCacheClass.getDeclaredConstructor().newInstance();
var putMethod = weakCacheClass.getDeclaredMethod("put", Object.class, Object.class);
var getMethod = weakCacheClass.getDeclaredMethod("get", Object.class);
putMethod.invoke(weakCache, "name", "bennyhuo");
System.out.println(getMethod.invoke(weakCache, "name"));
} catch (Exception e) {
e.printStackTrace();
}

7352D343.gif

满怀欣喜的运行它。。。

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
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:392)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:674)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:489)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at com.bennyhuo.java17.ReflectionsInternal.useWeakCache(ReflectionsInternal.java:16)
at com.bennyhuo.java17.ReflectionsInternal.main(ReflectionsInternal.java:10)

en???这让我想起了 Android P,你看这个字母 P,它的发音充满了挑衅,它的形状还有点儿像官方在嘲笑我们

73940E6B.gif

现在 Java 17 也玩这个啊,反射都不行了啊这。。

Java 16 我们可以通过在运行时加入 --illegal-access=permit 来运行,虽然会有一堆警告:

# java --illegal-access=permit com.bennyhuo.java17.ReflectionsInternal

Java HotSpot(TM) 64-Bit Server VM warning: Option --illegal-access is deprecated and will be removed in a future release.
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.bennyhuo.java17.ReflectionsInternal (file:/mnt/c/Users/benny/WorkSpace/Mario/SourceCode/Java17UpdatesDemo/src/) to constructor com.sun.beans.WeakCache()
WARNING: Please consider reporting this to the maintainers of com.bennyhuo.java17.ReflectionsInternal
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
bennyhuo

不过正如我们前面所说,Java 17 当中这个参数无效了:

# java --illegal-access=permit com.bennyhuo.java17.ReflectionsInternal

Java HotSpot(TM) 64-Bit Server VM warning: Ignoring option --illegal-access=permit; support was removed in 17.0
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 @372f7a8
d
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:392)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:674)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:489)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at com.bennyhuo.java17.ReflectionsInternal.useWeakCache(ReflectionsInternal.java:16)
at com.bennyhuo.java17.ReflectionsInternal.main(ReflectionsInternal.java:10)

这就是上帝在关门的时候(Java 9),顺便也提醒我们窗户也马上要关上了,还不赶紧滚出去?然后上帝又花了三年把窗户也关上了(Java 17)。不过,它总算是还留了一个通气孔。。。

0B24BC5A.png

Java 17 当中 –add-opens 仍然有效,通过开启它可以让我们的程序在运行时通过反射访问指定的类:

--add-opens java.desktop/com.sun.beans=ALL-UNNAMED

所以,上面的代码想要运行,只能:

# java --add-opens java.desktop/com.sun.beans=ALL-UNNAMED com.bennyhuo.java17.ReflectionsInternal

bennyhuo

所以这波限制是要来真的,赶快跑吧!

739B92AC.jpg

大家也可以参考 受影响的 API 清单 来规划自己的 JDK 升级。

顺便说一句,著名的 Unsafe 类不在这一波制裁的名单以内,可能是 Unsafe 应用太广泛了吧,而且 Java 官方也没有找到合适的替代品来满足需求,就先放着了(Unsafe 我们在后面访问堆外内存的内容中还会有介绍)。

好啦,关于加强控制内部 API 的限制的更新,我们也就介绍这么多,对大家的影响嘛,应该也不大(只要不升级)。


C 语言是所有程序员应当认真掌握的基础语言,不管你是 Java 还是 Python 开发者,欢迎大家关注我的新课 《C 语言系统精讲》:

扫描二维码或者点击链接《C 语言系统精讲》即可进入课程

program_in_c.png


Kotlin 协程对大多数初学者来讲都是一个噩梦,即便是有经验的开发者,对于协程的理解也仍然是懵懵懂懂。如果大家有同样的问题,不妨阅读一下我的新书《深入理解 Kotlin 协程》,彻底搞懂 Kotlin 协程最难的知识点:

扫描二维码或者点击链接《深入理解 Kotlin 协程》购买本书

understanding_kotlin_coroutines.png


如果大家想要快速上手 Kotlin 或者想要全面深入地学习 Kotlin 的相关知识,可以关注我基于 Kotlin 1.3.50 全新制作的入门课程:

扫描二维码或者点击链接《Kotlin 入门到精通》即可进入课程

exported_qrcode_image_256.png


Android 工程师也可以关注下《破解Android高级面试》,这门课涉及内容均非浅尝辄止,除知识点讲解外更注重培养高级工程师意识:

扫描二维码或者点击链接《破解Android高级面试》即可进入课程

15520936284634.jpg


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK