Javac + Lombok 阶段后如何使用 AspectJ Maven 进行二进制编织

问题描述 投票:0回答:1

我有一个项目,它使用已编译的方面并在编译时编织它们。我想添加Lombok,但不幸的是Lombok不支持AJC。由于这个项目本身没有任何方面的来源,所以在使用 Javac+Lombok 编译后,我配置了 AspectJ Maven 插件来进行编译后编织。

这是 AspectJ Maven 插件的配置:

<forceAjcCompile>true</forceAjcCompile>
<sources/>
<weaveDirectory>${project.build.outputDirectory}</weaveDirectory>

它在 Maven 编译器插件编译后立即附加到编译阶段。这样,Lombok + Javac 将首先被调用,然后 AJC 将在 Javac 生成的类文件上执行编织。

在 javac 生成的类上执行字节码编织时是否有任何限制/缺点?

也许有更好的方法让 Maven+Lombok+Aspects+Idea 毫无问题地协同工作。

这是一个最小的示例项目:https://github.com/Psimage/aspectj-and-lombok

java maven aspectj lombok aspectj-maven-plugin
1个回答
10
投票

当您在评论中问我另一个问题时,我实际上认为您的方法有问题,但它确实有效。为了直接从 IDE (IntelliJ IDEA) 运行测试,我唯一要做的就是将应用程序和测试运行程序实际委托给 Maven,否则 IDEA 不会同时应用 Lombok + AspectJ。

如果您的方法有效,请使用它。但实际上AspectJ Maven建议另一种方法:首先使用Maven编译器编译到另一个输出目录,然后使用该目录作为AspectJ编译器的weave目录。不过,示例 POM 并不能 100% 工作,因为在命令行上指定 Javac 的输出目录时,该目录需要存在,但编译器不会创建它。所以你也需要一些丑陋的 Antrun 动作:

<plugins>

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-antrun-plugin</artifactId>
    <version>1.8</version>
    <executions>
      <execution>
        <id>unwovenClassesFolder</id>
        <phase>generate-resources</phase>
        <configuration>
          <tasks>
            <delete dir="${project.build.directory}/unwoven-classes"/>
            <mkdir dir="${project.build.directory}/unwoven-classes"/>
          </tasks>
        </configuration>
        <goals>
          <goal>run</goal>
        </goals>
      </execution>
    </executions>
  </plugin>

  <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <executions>
      <execution>
        <!-- Modifying output directory of default compile because non-weaved classes must be stored
             in separate folder to not confuse ajc by reweaving already woven classes (which leads to
             to ajc error message like "bad weaverState.Kind: -115") -->
        <id>default-compile</id>
        <configuration>
          <compilerArgs>
            <arg>-d</arg>
            <arg>${project.build.directory}/unwoven-classes</arg>
          </compilerArgs>
        </configuration>
      </execution>
    </executions>
  </plugin>

  <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <configuration>
      <aspectLibraries>
        <aspectLibrary>
          <groupId>me.yarosbug</groupId>
          <artifactId>aspects</artifactId>
        </aspectLibrary>
      </aspectLibraries>

      <forceAjcCompile>true</forceAjcCompile>
      <sources/>
      <weaveDirectories>
        <weaveDirectory>${project.build.directory}/unwoven-classes</weaveDirectory>
      </weaveDirectories>
    </configuration>
    <executions>
      <execution>
        <phase>process-classes</phase>
        <goals>
          <goal>compile</goal>
        </goals>
      </execution>
    </executions>
  </plugin>

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.2</version>
  </plugin>

</plugins>

我建议另一种方法作为替代:

  1. 创建一个未编织的 Java 模块,在那里执行 Java + Lombok 的操作。
  2. 为 AspectJ 二进制编织创建一个单独的模块,使用 Java 模块作为编织依赖项。因为你的单元测试同时依赖于 Lombok 和 AspectJ,所以将测试放在这个模块中。

优点是不需要摆弄多个编译器、执行阶段、输出目录、Antrun等


更新:

我克隆了您的 GitHub MCVE分支上的此提交 master 反映了我在上面的示例 XML 中所解释的内容。

我还创建了一个分支多阶段编译另一个提交,它根据我的替代想法有效地重构了项目。我只是引用提交消息:

Multi-phase compilation: 1. Java + Lombok, 2. AspectJ binary weaving

There are many changes (sorry, I should have split them into multiple
commits):
  - Marker annotation renamed to @marker and moved to separate module
    because the main application should not depend on the aspect module.
    Rather both application and aspect now depend on a common module.
  - New module "main-app-aspectj" does only AspectJ binary weaving on
    the already lomboked Java application.
  - Both application modules have slightly different unit tests now: One
    checks that Lombok has been applied and AspectJ has not, the other
    checks that both have been applied.
  - Aspect pointcut limits matching to "execution(* *(..))" in order to
    avoid also matching "call()" joinpoints.

The end result is that now we have a clear separation of concerns, clear
dependencies, no more scripted Ant build components and the new option
to use the lomboked code optionally with or without aspects applied
because both types or JARs are created during the build.

随意将我的分支作为另一个远程添加到您的 Git 存储库,并从那里提取我的更改。如果您希望我向您发送拉取请求以使其更容易,请告诉我。

更新2,2023年12月16日:

我出于另一个原因重新审视了这个主题,并意识到,上次我没有提到一件重要的事情:在具有中介、未编织和最终的编织模块的多模块方法中,前者应该使用

provided
范围进行声明在后者中,因为我们希望避免未编织的模块最终出现在其他模块的类路径上,具体取决于编织的模块。这很重要,因为否则两组(重复但不同的)类最终会出现在类路径上,并且根据确切的类加载情况,可以先找到其中任何一个。

因此,我向多模块分支添加了一些提交,清理了情况并添加了一个依赖模块并对类路径内容进行测试,以确保一切按预期工作。

© www.soinside.com 2019 - 2024. All rights reserved.