Java9之后的模块化烦恼解决(由RocketMQ升级OpenJDK11想到的)

本文基于OpenJDK11
最近从OpenJDK8升级到了OpenJDK11,系统业务MQ用的RocketMQ,升级RocketMQ过程中,在已修改好JVM参数的情况下(参考我另一篇文章),遇到如下异常:
java.lang.IllegalStateException: java.lang.reflect.InaccessibleObjectException: Unable to make public void jdk.internal.ref.Cleaner.clean() accessible: module java.base does not "exports jdk.internal.ref" to unnamed module @3590fc5b at org.apache.rocketmq.store.MappedFile$1.run(MappedFile.java:105) ~[rocketmq-store-4.5.0.jar:4.5.0] at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na] at org.apache.rocketmq.store.MappedFile.invoke(MappedFile.java:98) ~[rocketmq-store-4.5.0.jar:4.5.0] at org.apache.rocketmq.store.MappedFile.clean(MappedFile.java:94) ~[rocketmq-store-4.5.0.jar:4.5.0] at org.apache.rocketmq.store.MappedFile.cleanup(MappedFile.java:434) ~[rocketmq-store-4.5.0.jar:4.5.0] at org.apache.rocketmq.store.ReferenceResource.release(ReferenceResource.java:63) ~[rocketmq-store-4.5.0.jar:4.5.0] at org.apache.rocketmq.store.ReferenceResource.shutdown(ReferenceResource.java:47) ~[rocketmq-store-4.5.0.jar:4.5.0] at org.apache.rocketmq.store.MappedFile.destroy(MappedFile.java:442) ~[rocketmq-store-4.5.0.jar:4.5.0] at org.apache.rocketmq.store.index.IndexFile.destroy(IndexFile.java:89) ~[rocketmq-store-4.5.0.jar:4.5.0] at org.apache.rocketmq.store.index.IndexService.load(IndexService.java:71) ~[rocketmq-store-4.5.0.jar:4.5.0] at org.apache.rocketmq.store.DefaultMessageStore.load(DefaultMessageStore.java:195) ~[rocketmq-store-4.5.0.jar:4.5.0] at org.apache.rocketmq.broker.BrokerController.initialize(BrokerController.java:256) ~[rocketmq-broker-4.5.0.jar:4.5.0] at org.apache.rocketmq.broker.BrokerStartup.createBrokerController(BrokerStartup.java:218) ~[rocketmq-broker-4.5.0.jar:4.5.0] at org.apache.rocketmq.broker.BrokerStartup.main(BrokerStartup.java:58) ~[rocketmq-broker-4.5.0.jar:4.5.0] Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make public void jdk.internal.ref.Cleaner.clean() accessible: module java.base does not "exports jdk.internal.ref" to unnamed module @3590fc5b at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:340) ~[na:na] at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:280) ~[na:na] at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:198) ~[na:na] at java.base/java.lang.reflect.Method.setAccessible(Method.java:192) ~[na:na] at org.apache.rocketmq.store.MappedFile$1.run(MappedFile.java:102) ~[rocketmq-store-4.5.0.jar:4.5.0] ... 13 common frames omitted复制代码

这个就是模块化导致的缺陷了,我们知道,在Java9之后引入了模块化的概念,是将类型和资源封装在模块中,并仅导出其他模块要访问其公共类型的软件包。如果模块中的软件包未导出或打开,则表示模块的设计人员无意在模块外部使用这些软件包。 这样的包可能会被修改或甚至从模块中删除,无需任何通知。 如果仍然使用这些软件包通过使用命令行选项导出或打开它们,可能会面临破坏应用程序的风险!
那么对于上面这个异常,我们怎么解决呢?可以通过加入启动参数。
首先,这类异常一般符合下面这个模板:
Unable to make {member} accessible: module {A} does not '{operation} {package}' to {B}复制代码

我们根据operation,决定要加的启动参数:
operation jvm启动参数
exports --add-exports
opens --add-opens
requires --add-reads
然后拼接启动参数:
{上面的jvm启动参数} {A}/{package}={B}复制代码

上面的异常需要的参数就是(ALL-UNNAMED代表所有jdk编译出来的匿名类):
--add-exports java.base/jdk.internal.ref=ALL-UNNAMED复制代码

更多请参考Java 9 揭秘(9. 打破模块封装)
【Java9之后的模块化烦恼解决(由RocketMQ升级OpenJDK11想到的)】

    推荐阅读