如何将 class 注入 java.lang 包
How to inject a class into the java.lang package
在 OpenJDK 11 上尝试通过 java.lang.instrument.Instrumentation#appendToBootstrapClassLoaderSearch
注入位于 java.lang
命名空间中的 class 时,没有任何反应,也没有抛出任何错误。当放置 class 以注入到不同的包中时,它按预期工作。
JarFile jar = new JarFile(new File("file/to/bootstrap.jar));
instrumentation.appendToBootstrapClassLoaderSearch(jar);
// throws ClassNotFoundException java/lang/Dispatcher
Class.forName("java.lang.Dispatcher", false, null);
bootstrap.jar
└─ java/lang/Dispatcher.class
我想这样做的原因是为了克服一些 OSGi 容器的问题。他们通常将对 bootstrap class 加载程序的委派限制为仅某些包。默认情况下,显然总是包含 java.*
这就是为什么我想把我的 Dispatcher
class 放在那里。我知道 org.osgi.framework.bootdelegation
但 属性 只在初始化期间被读取。这意味着在运行时附加代理时,覆盖此值已经太迟了。
另一种方法是检测所有已知的 OSGi class 加载器并将代理 classes 列入白名单。但是对每个框架都这样做并针对每个版本进行测试似乎不太可行。
如何将 class 之类的自定义 java.lang.Dispatcher
注入到 bootstrap class 加载程序中?是否有其他模式或最佳实践来避免 OSGi 引导委托问题?
提供更多背景信息:
我的想法是只将这个Dispatcher
class注入bootstrapclass加载器。调度程序基本上只是持有一个静态地图。代理的其余 classes 将由专用的 URLClassLoader 加载,它是 bootstrap class 加载程序的子项。然后,代理将在调度程序的 Map 中注册 MethodHandle
s,以便注入的字节代码可以获取 MethodHandles,从而能够访问代理 class 加载到代理 class 加载程序中的 es。
可以通过使用不安全 API。自 Java 9 起,引导 class 加载程序的实现已更改为仅检查指定的 jmod 以查找已知包,但不再检查引导搜索路径。
Java 11 也删除了 sun.misc.Unsafe#defineClass
方法,但相同的方法在 jdk.internal.misc.Unsafe
.
中仍然可用
您必须打开 class 的内部模块。您可以通过使用 sun.misc.Unsafe
来实现,它允许您在不进行可访问性检查的情况下编写字段值 (accessible
),或者使用 Instrumentation 的官方 API.
如果您使用的是 Byte Buddy,请查看 ClassInjector
实现,它提供了所有方法的实现。
有一个 open ticket for adressing the need of Java agents to inject helper classes,但在解决之前,这是一个常见的解决方法。
在 OpenJDK 11 上尝试通过 java.lang.instrument.Instrumentation#appendToBootstrapClassLoaderSearch
注入位于 java.lang
命名空间中的 class 时,没有任何反应,也没有抛出任何错误。当放置 class 以注入到不同的包中时,它按预期工作。
JarFile jar = new JarFile(new File("file/to/bootstrap.jar));
instrumentation.appendToBootstrapClassLoaderSearch(jar);
// throws ClassNotFoundException java/lang/Dispatcher
Class.forName("java.lang.Dispatcher", false, null);
bootstrap.jar
└─ java/lang/Dispatcher.class
我想这样做的原因是为了克服一些 OSGi 容器的问题。他们通常将对 bootstrap class 加载程序的委派限制为仅某些包。默认情况下,显然总是包含 java.*
这就是为什么我想把我的 Dispatcher
class 放在那里。我知道 org.osgi.framework.bootdelegation
但 属性 只在初始化期间被读取。这意味着在运行时附加代理时,覆盖此值已经太迟了。
另一种方法是检测所有已知的 OSGi class 加载器并将代理 classes 列入白名单。但是对每个框架都这样做并针对每个版本进行测试似乎不太可行。
如何将 class 之类的自定义 java.lang.Dispatcher
注入到 bootstrap class 加载程序中?是否有其他模式或最佳实践来避免 OSGi 引导委托问题?
提供更多背景信息:
我的想法是只将这个Dispatcher
class注入bootstrapclass加载器。调度程序基本上只是持有一个静态地图。代理的其余 classes 将由专用的 URLClassLoader 加载,它是 bootstrap class 加载程序的子项。然后,代理将在调度程序的 Map 中注册 MethodHandle
s,以便注入的字节代码可以获取 MethodHandles,从而能够访问代理 class 加载到代理 class 加载程序中的 es。
可以通过使用不安全 API。自 Java 9 起,引导 class 加载程序的实现已更改为仅检查指定的 jmod 以查找已知包,但不再检查引导搜索路径。
Java 11 也删除了 sun.misc.Unsafe#defineClass
方法,但相同的方法在 jdk.internal.misc.Unsafe
.
您必须打开 class 的内部模块。您可以通过使用 sun.misc.Unsafe
来实现,它允许您在不进行可访问性检查的情况下编写字段值 (accessible
),或者使用 Instrumentation 的官方 API.
如果您使用的是 Byte Buddy,请查看 ClassInjector
实现,它提供了所有方法的实现。
有一个 open ticket for adressing the need of Java agents to inject helper classes,但在解决之前,这是一个常见的解决方法。