jdk.dynalink 在 Java 9 的引导类路径中不可见

jdk.dynalink not visible from bootclasspath in Java 9

我们的项目是使用 Eclipse OSGi 开发的,但也通过 jardesc 文件提供普通的 JAR 用于导出。该项目使用 ASM 库和 javaagent 来交换 invokevirtualinvokedynamic 调用。

这在 Java 7 和 8 中运行良好。现在,我们升级到 Java 9 并将我们的实现移植到使用 jdk.dynalink.

java --version`
java 9.0.4
Java(TM) SE Runtime Environment (build 9.0.4+11)
Java HotSpot(TM) 64-Bit Server VM (build 9.0.4+11, mixed mode)

导出的部分

目前,OTRE_MIN 还包括 OTRE_DYN。所以所有东西都放到bootclasspath.

我用下面的代码启动程序

JVM_ARGS="-d64 -Xms1024m -Xmx4048m -ea"
MODULES="--add-reads jdk.dynalink=ALL-UNNAMED --add-reads java.base=ALL-UNNAMED"

${JAVA_HOME}bin/java $MODULES \
-Xbootclasspath/a:${OTRE_MIN} -javaagent:$OTREDYN_AGENT $JVM_ARGS \
-jar ...

但是,jdk.dynalink包似乎在引导class路径上不再可见。

java.lang.NoClassDefFoundError: jdk/dynalink/linker/GuardingDynamicLinker
at org.eclipse.objectteams.otredyn.runtime.dynamic.CallinBootstrap.<clinit>(CallinBootstrap.java:19)
at org.eclipse.objectteams.otredyn.bytecode.asm.CreateCallAllBindingsCallInOrgMethod.<clinit>(CreateCallAllBindingsCallInOrgMethod.java:115)
at org.eclipse.objectteams.otredyn.bytecode.asm.AsmWritableBoundClass.createCallAllBindingsCallInOrgMethod(AsmWritableBoundClass.java:300)
at org.eclipse.objectteams.otredyn.bytecode.AbstractBoundClass.weaveBindingInImplementedMethod(AbstractBoundClass.java:1180)
at org.eclipse.objectteams.otredyn.bytecode.AbstractBoundClass.handleTaskList(AbstractBoundClass.java:741)
at org.eclipse.objectteams.otredyn.bytecode.AbstractBoundClass.transformAtLoadTime(AbstractBoundClass.java:383)
at org.eclipse.objectteams.otredyn.transformer.jplis.ObjectTeamsTransformer.transform(ObjectTeamsTransformer.java:120)
at org.eclipse.objectteams.otredyn.transformer.jplis.ObjectTeamsTransformer.transform(ObjectTeamsTransformer.java:72)
at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:246)
at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:550)
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1007)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174)
at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:801)
at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:699)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:622)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:185)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)
at BankBenchmark2.setUp(BankBenchmark2.java:32)
at Run.doRuns(Run.java:55)
at Run.runBenchmark(Run.java:29)
at Harness.main(Harness.java:34)

我阅读了其他关于 Java 9 和模块系统以及对 class 加载程序的更改的线程,但他们没有提供任何解决问题的方法。

如何使 jdk.dynalink$OTRE_MIN 的 class 可见,就像 Java 9 之前一样?

解决方案是更加注意 class 路径层次结构的填充和使用方式。 Java 9 使您对此考虑得更多,因为并非所有模块都始终可见。

我将 jar 分开,以便它们针对每个关注点分开:javaagent、加载时编织。现在,最小运行时间 (OTRE_MIN) 在 bootclass 路径中可见。其余部分通过 OTRE_DYN 添加到应用程序的正常 class 路径。 OTRE_AGENT 保持 javaagent 不变。

JVM_ARGS="-d64 -Xms1024m -Xmx4048m -ea"
MODULES="--add-reads jdk.dynalink=ALL-UNNAMED --add-reads java.base=ALL-UNNAMED"

${JAVA_HOME}bin/java $MODULES \
  -Xbootclasspath/a:${OTRE_MIN} -javaagent:$OTREDYN_AGENT $JVM_ARGS -cp ${OTRE_DYN} \
  -jar ...

但是,这只是避免了在引导class路径中使用jdk.dynlink,问题仍然有待回答。