简体   繁体   English

如何将类注入java.lang包中

[英]How to inject a class into the java.lang package

When trying to inject a class which is in the java.lang namespace via java.lang.instrument.Instrumentation#appendToBootstrapClassLoaderSearch on a OpenJDK 11, nothing happens and no error is thrown. 当尝试通过OpenJDK 11上的java.lang.instrument.Instrumentation#appendToBootstrapClassLoaderSearch注入java.lang命名空间中的类时,没有任何反应并且不会引发错误。 When placing the class to inject into a different package, it works as expected. 将类放入注入不同的包时,它按预期工作。

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

The reason I want to do this is to overcome issues with some OSGi containers. 我想这样做的原因是为了克服一些OSGi容器的问题。 They typically restrict delegation to the bootstrap class loader to only certain packages. 它们通常将对bootstrap类加载器的委派限制为仅限于某些包。 By default that obviously always includes java.* which is why I want to put my Dispatcher class there. 默认情况下,显然总是包含java.*这就是为什么我想把Dispatcher类放在那里。 I'm aware of org.osgi.framework.bootdelegation but that property only gets read during initialization. 我知道org.osgi.framework.bootdelegation但该属性仅在初始化期间被读取。 That means when attaching an agent at runtime, it's already too late to override this value. 这意味着在运行时附加代理时,覆盖此值已经太晚了。

An alternative would be to instrument all known OSGi class loaders and to white-list the agent classes. 另一种方法是检测所有已知的OSGi类加载器并将代理类列入白名单。 But doing that for each framework and test that for each version seems less feasible. 但是为每个框架执行此操作并测试每个版本似乎不太可行。

How can I inject a custom class like java.lang.Dispatcher into the bootstrap class loader? 如何将自定义类(如java.lang.Dispatcher注入引导类加载器? Are there other patterns or best practices to avoid OSGi bootdelegation issues? 是否有其他模式或最佳实践来避免OSGi bootdelegation问题?

To provide some more context: 提供更多背景信息:

My idea is to only inject this one Dispatcher class into the bootstrap class loader. 我的想法是只将这个Dispatcher类注入bootstrap类加载器。 The dispatcher basically just holds a static Map. 调度程序基本上只包含一个静态Map。 The rest of the agent's classes would be loaded by a dedicated URLClassLoader which is a child of the bootstrap class loader. 代理程序的其余类将由专用的URLClassLoader加载,该类是引导类加载器的子代。 The agent would then register MethodHandle s in the dispatcher's Map so that the injected byte code can get ahold of the MethodHandles which enable accessing the agent's classes loaded in the agent class loader. 然后代理将在调度程序的Map中注册MethodHandle ,以便注入的字节代码可以获得MethodHandles,它允许访问代理程序类加载器中加载的代理程序的类。

It is possible by using unsafe API. 可以使用不安全的API。 Since Java 9, the boot class loader's implementation has changed to only check a designated jmod for a known package, but the boot search path is no longer checked. 从Java 9开始,引导类加载器的实现已更改为仅检查已指定包的指定jmod,但不再检查引导搜索路径。

Java 11 also removed the sun.misc.Unsafe#defineClass method but the same method is still available in jdk.internal.misc.Unsafe . Java的11也去掉了sun.misc.Unsafe#defineClass方法,但同样的方法仍然可用在jdk.internal.misc.Unsafe

You do have to open that class's module which is internal. 你必须打开该类的内部模块。 You can either do so by using sun.misc.Unsafe which allows you to write a field value ( accessible ) without accessibility checks or by using Instrumentation's official API. 您可以使用sun.misc.Unsafe执行此操作,它允许您编写字段值( accessible )而无需可访问性检查或使用Instrumentation的官方API。

If you are using Byte Buddy, have a look at the ClassInjector implementations which offer implementations for all approaches. 如果您正在使用Byte Buddy,请查看为所有方法提供实现的ClassInjector实现。

There is an open ticket for adressing the need of Java agents to inject helper classes but until it is resolved, this is a common workaround. 有一个开放的票据可以解释Java代理注入帮助程序类的需要,但在解决之前,这是一个常见的解决方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM