当尝试通过 java.lang.instrument.Instrumentation#appendToBootstrapClassLoaderSearch
注入(inject) java.lang
命名空间中的类时在 OpenJDK 11 上,没有任何反应,也没有抛出任何错误。将类注入(inject)到不同的包中时,它按预期工作。
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 容器的问题。他们通常将对引导类加载器的委托(delegate)仅限于某些包。默认情况下,它显然总是包含 java.*
,这就是为什么我想将我的 Dispatcher
类放在那里。我知道 org.osgi.framework.bootdelegation
但该属性仅在初始化期间读取。这意味着在运行时附加代理时,覆盖此值已经太晚了。
另一种方法是检测所有已知的 OSGi 类加载器并将代理类列入白名单。但是针对每个框架执行此操作并针对每个版本进行测试似乎不太可行。
如何将自定义类(如 java.lang.Dispatcher
)注入(inject)引导类加载器?是否有其他模式或最佳实践来避免 OSGi 引导委托(delegate)问题?
提供更多上下文:
我的想法是只将这个 Dispatcher
类注入(inject)引导类加载器。调度程序基本上只是持有一个静态 map 。代理的其余类将由专用的 URLClassLoader 加载,它是引导类加载器的子级。然后,代理将在调度程序的映射中注册 MethodHandle
,以便注入(inject)的字节代码可以获取 MethodHandles,从而能够访问代理类加载器中加载的代理类。
最佳答案
使用不安全的 API 是可能的。从 Java 9 开始,引导类加载器的实现已更改为仅检查指定的 jmod 以查找已知包,但不再检查引导搜索路径。
Java 11 还删除了 sun.misc.Unsafe#defineClass
方法,但相同的方法在 jdk.internal.misc.Unsafe
中仍然可用。
您必须打开该类的内部模块。您可以通过使用 sun.misc.Unsafe
来执行此操作,它允许您编写字段值 (accessible
) 而无需进行可访问性检查,或者使用 Instrumentation 的官方 API。
如果您使用的是 Byte Buddy,请查看 ClassInjector
为所有方法提供实现的实现。
有一个open ticket for adressing the need of Java agents to inject helper classes但在问题得到解决之前,这是一种常见的解决方法。
关于java - 如何将一个类注入(inject)到java.lang包中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57451427/