在'fat jar'中指定java代理?

Posted

技术标签:

【中文标题】在\'fat jar\'中指定java代理?【英文标题】:Specify java agent inside 'fat jar'?在'fat jar'中指定java代理? 【发布时间】:2016-12-26 07:02:43 【问题描述】:

我正在使用 jetty-alpn-agent 为我的项目添加 ALPN 支持,但我只能找到有关如何从 .m2 文件夹运行它的说明,这使我需要部署两个 jar:s 而不仅仅是我的一个 uber-jar,使其不那么便携。

是否可以为 -javaagent 开关指定 jar 内的位置?

我正在寻找类似java -javaagent:my.jar!/javaagents/jetty-alpn-agent-2.0.0.jar -jar myjar.jar 的东西,但这似乎不起作用。

【问题讨论】:

【参考方案1】:

根据java.lang.instrumentation 文档可能是可能的。

如果实现允许,jetty-alpn-agent.jar 必须是系统类路径的一部分。因此,您必须像任何其他应用程序库一样将其包含在您的 my.jar 中。

虚拟机启动后启动代理

实现可能会提供一种机制,以便在 VM 启动后的某个时间启动代理。关于如何启动的细节是特定于实现的,但通常应用程序已经启动并且它的 main 方法已经被调用。如果实现支持在 VM 启动后启动代理,则适用以下情况:

代理 JAR 的清单必须包含属性 Agent-Class。该属性的值为代理类的名称。

代理类必须实现一个公共静态agentmain方法。

系统类加载器 (ClassLoader.getSystemClassLoader) 必须支持将代理 JAR 文件添加到系统类路径的机制。

代理 JAR 附加到系统类路径。这是通常加载包含应用程序主方法的类的类加载器。代理类被加载,JVM 尝试调用 agentmain 方法。 JVM 首先尝试在代理类上调用以下方法:

public static void agentmain(String agentArgs, Instrumentation inst);

如果代理类没有实现这个方法,那么JVM会尝试调用:

public static void agentmain(String agentArgs);

代理类也可能有一个 premain 方法,用于在使用命令行选项启动代理时使用。在 VM 启动后启动代理时,不会调用 premain 方法。

代理通过 agentArgs 参数传递其代理选项。代理选项作为单个字符串传递,任何额外的解析都应该由代理自己执行。

agentmain 方法应该执行启动代理所需的任何必要初始化。启动完成后,该方法应返回。如果无法启动代理(例如,因为无法加载代理类,或者因为代理类没有符合的 agentmain 方法),则 JVM 不会中止。如果 agentmain 方法抛出未捕获的异常,它将被忽略。

PS:我从来没有试过这个。请让我知道它是否有效。

【讨论】:

谢谢,这可能是更多“简单”代理 jar 的一个选项,但是这个特殊的 jar jar 包含在其中,我还需要创建实现“agentmain()”方法的包装类( s),这会在尝试加载时导致类路径问题。我想我会硬着头皮把它添加到agents 目录中,然后将它添加到启动脚本中。从长远来看,我们迁移到的平台会在部署时自动检测到这个代理 jar,所以我可以把它作为一个临时解决方案。 运行时附件不保证在附件时尚未加载类。但是,加载的类只能更改以提供不同的方法实现,而不允许使用不同的形状。【参考方案2】:

您可以通过将 premain 类写入 fat jar 的清单来模拟以前的代理。然后,只需通过 javaagentjar 参数添加您的胖 jar。

无法避免这种情况,因为检测 API 非常强大,并且允许避免安全管理器提供攻击入口点。但是,您可以在 JDK 或 Java 9 VM 上进行自连接。 byte-buddy-agent 库为此提供了现成的依赖项。这样,您可以在获取检测实例后手动调用您的 premain 方法。

【讨论】:

以上是关于在'fat jar'中指定java代理?的主要内容,如果未能解决你的问题,请参考以下文章

java - 如何在Java文件中指定相对文件路径,以便将文件放入jar文件后仍然可以工作?

Java 获取Word中指定图片的坐标位置

我可以在配置文件中指定 ninja.port 吗?

fat jar怎么用

从 Java 代码中指定 DIP 尺寸的正确方法是啥?

在 java.nio 中指定连接超时