如何从我自己的 Maven 库中修改项目的 Maven 测试执行阶段的命令行参数?

问题描述

我想创建一个 Maven 库,它将作为测试的辅助工具,因此它只会在测试阶段使用,就像 HamcrestAssertJ 等一样。这个库需要一个Java 代理正常运行,并且此 Java 代理需要在启动时加载,在运行时加载(因此通过命令行选项 -javaagent)?

假设有一个(第三方)应用程序使用我的 Maven 库,如下所示:

 <dependency>
    <groupId>my.org</groupId>
    <artifactId>my.library</artifactId>
    <version>1.0</version>
    <scope>test</scope>
 </dependency>

在我的库中,我的代理将封装在 jar 中,但也会有一些其他代码来帮助加载代理。因此,当在第三方应用程序中运行测试时,我的库中的 Java 代理应该会在没有任何用户干预的情况下自动加载(因此唯一必要的步骤是将我的库添加为依赖项)。

如何在加载时加载此代理?是否有可能?如果使用简单的 Maven 库无法实现,是否可以改为创建 Maven 插件(因此第三方应用程序将我的插件包含在 pom.xml 中)?

我想在加载时加载代理而不是运行时加载代理的原因是在Java 9之后,需要在命令行中添加-Djdk.attach.allowAttachSelf=true以允许在运行时加载代理,那么为什么如果我可以添加 -javaagent

,请添加该参数

解决方法

你不能。想象一下,如果没有用户的知识并且除了添加您的依赖项之外没有任何其他操作,您将转换她的应用程序字节码!

添加依赖项是一回事,但通过调用方法或启动 Java 代理来激活它又是另一回事。这应该在客户端应用程序的控制之下。可以在运行时在不使用 -javaagent: 的情况下附加 Java 代理,但客户端应用程序必须通过调用代理提供程序中的初始化方法来显式执行此操作。如果您和您的用户之间存在该契约,即如果用户通过调用该假设的初始化方法进行合作(在您要修改的类加载之前足够早),您可以这样做。

有什么大不了的?您希望为用户提供代理功能。为什么他们不能像往常一样启动代理? JVM命令行加个参数这么费劲吗?


在 OP 还编辑了问题之后更新: 对于 Maven Surefire(单元测试)或其孪生 Maven Failsafe(集成测试),您希望使用 argLine 参数以便在命令行上使用 Java 代理启动目标 JVM。有关示例,请参阅 my answer here。都是在命令行用AspectJ编织代理开始测试,但是原理是一样的。基本上,它是这样的:

<properties>
  <myDependency.version>1.2.3</myDependency.version>
</properties>

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.9</version>
  <configuration>
    <argLine>
      -javaagent:${settings.localRepository}/my/group-id/my-dependency/${myDependency.version}/my-dependency-${myDependency.version}.jar
    </argLine>
  </configuration>
  <dependencies>
    <dependency>
      <groupId>my.group-id</groupId>
      <artifactId>my-dependency</artifactId>
      <version>${myDependency.version}</version>
    </dependency>
  </dependencies>
</plugin>

您只需要记录如何使用您的测试代理,以便您的所有下游用户都了解它。

如果您不想半手动指定代理的路径,您可以使用 Maven Dependency Plugin 的 dependency:properties 目标来自动生成所有依赖项,包含路径名。但这不是必须的,只是锦上添花。