【问题标题】:How to inject a class into the java.lang package如何将类注入 java.lang 包
【发布时间】:2019-08-11 15:47:31
【问题描述】:

当尝试在 OpenJDK 11 上通过 java.lang.instrument.Instrumentation#appendToBootstrapClassLoaderSearch 注入位于 java.lang 命名空间中的类时,没有任何反应,也不会引发错误。将要注入的类放入不同的包中时,它会按预期工作。

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 容器的问题。它们通常将对引导类加载器的委托限制为仅限于某些包。默认情况下,显然总是包含java.*,这就是为什么我想把我的Dispatcher 类放在那里。我知道org.osgi.framework.bootdelegation 但该属性仅在初始化期间被读取。这意味着在运行时附加代理时,覆盖该值已经太迟了。

另一种方法是检测所有已知的 OSGi 类加载器并将代理类列入白名单。但是对每个框架都这样做并针对每个版本进行测试似乎不太可行。

如何将java.lang.Dispatcher 之类的自定义类注入引导类加载器?是否有其他模式或最佳实践来避免 OSGi 引导委托问题?

提供更多上下文:

我的想法是只将这个Dispatcher 类注入到引导类加载器中。调度程序基本上只是持有一个静态地图。代理的其余类将由一个专用的 URLClassLoader 加载,该 URLClassLoader 是引导类加载器的子类。然后代理将在调度程序的 Map 中注册MethodHandles,以便注入的字节码可以获取 MethodHandles,从而可以访问代理类加载器中加载的代理类。

【问题讨论】:

    标签: java classloader instrumentation


    【解决方案1】:

    可以使用不安全的 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,但在解决之前,这是一种常见的解决方法。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-03
    • 2017-02-06
    • 2011-01-05
    • 1970-01-01
    • 2018-12-17
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    相关资源
    最近更新 更多