在Javac +龙目岛阶段之后,如何使用AspectJ Maven进行二进制编织

时间:2019-07-11 19:32:19

标签: java maven aspectj lombok aspectj-maven-plugin

我有一个使用已编译方面的项目,并在编译时进行编织。我想添加Lombok,但是不幸的是Lombok不支持AJC。由于该项目本身没有任何方面的资源,因此在使用Javac + Lombok进行编译之后,我将AspectJ Maven插件配置为进行后编译编织。

这是AspectJ Maven插件的配置:

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

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

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

也许有更好的方法可以使Maven + Lombok + Aspects + Idea协同工作而没有问题。

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

1 个答案:

答案 0 :(得分:0)

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

Delegate IDE build/run actions to Maven

如果您的方法可行,请使用它。但是实际上AspectJ Maven建议使用another approach:首先使用Maven编译器编译到另一个输出目录,然后使用该目录作为AspectJ编译器的编织目录。但是,这里的示例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. 使用Java模块作为编织依赖项,为AspectJ二进制编织创建一个单独的模块。因为您的单元测试取决于Lombok和AspectJ,所以将测试放在此模块中。

优点是您无需费心处理多个编译器,执行阶段,输出目录,Antrun等。


更新

我克隆了您的GitHub MCVEthis commit on branch master反映了我在上面的示例XML中所解释的内容。

我还用branch multi-phase-compilation创建了一个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.

随意将我的fork作为另一个远程添加到您的Git存储库,并从那里提取我的更改。如果您希望我发送拉取请求以便于您轻松进行操作,请告诉我。