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

How to use AspectJ Maven for binary weaving after Javac + Lombok phase

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

这是 AspectJ Maven 插件的配置:

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

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

javac生成的classes执行字节码编织时是否有limitations/disadvantages?

也许有更好的方法让 Maven+Lombok+Aspects+Idea 一起工作而没有问题。

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

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

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

<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,所以把测试放在这个模块中。

优点是您不需要 fiddle 多个编译器、执行阶段、输出目录、Ant运行 等


更新:

我克隆了你的 GitHub MCVE and this commit on branch master 反映了我在上面的示例 XML 中解释的内容。

我还创建了一个 branch multi-phase-compilation with another commit,它根据我的替代想法有效地重构了项目。我只是引用提交信息:

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 存储库,并从那里提取我的更改。如果您希望我向您发送拉取请求以使其更容易,请告诉我。