【问题标题】:AspectJ Aspects not getting triggered in Maven ProjectAspectJ 方面未在 Maven 项目中触发
【发布时间】:2021-06-18 09:39:04
【问题描述】:

我正在尝试使用AspectJ 而不使用Spring AOP 来构建一个POC 项目。我正在使用基于注释的方法,我想在其中运行方面@Around 已使用注释进行注释的方法。出于某种原因,我的方面没有被触发。以下是我的代码:

pom.xml

<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.8.9</version>
    </dependency>

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.9</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.7</version>
            <configuration>
                <complianceLevel>1.8</complianceLevel>
                <source>1.8</source>
                <target>1.8</target>
                <showWeaveInfo>true</showWeaveInfo>
                <verbose>true</verbose>
                <Xlint>ignore</Xlint>
                <encoding>UTF-8</encoding>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <!-- use this goal to weave all your main classes -->
                        <goal>compile</goal>
                        <!-- use this goal to weave all your test classes -->
                        <goal>test-compile</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

资源/META-INF/aop.xml

<aspectj>
    <aspects>
        <aspect name="com.aditya.personal.aspects.MetricsAspect"/>
        <weaver options="-verbose -showWeaveInfo">
            <include within="com.carrot.personal.aspects.*"/>
        </weaver>
    </aspects>
</aspectj>

我的观点:

@Aspect
public class DataTrackAspect {

    @Around("@annotation(com.carrot.personal.aspects.DataTrackEnabled)")
    public Object performAspect(ProceedingJoinPoint joinPoint, DataTrackEnabled dataTrackEnabled) throws Throwable {

        Object result = joinPoint.proceed();
        DataTrackHelper dataTrackHelper = new DataTrackHelper();
        dataTrackHelper.recordInstanceCount(dataTrackEnabled.dataClass(), dataTrackEnabled.dataName(), dataTrackEnabled.instance());
        return result;
    }
}

带注释的方法

@DataTrackEnabled(dataClass = "Hey", dataName = "There", instance = "How are you?")
public Map<String, String> fetchUser() {
    Map<String, String> returnable = new HashMap<>();
    returnable.put("firstName", "carrot");
    returnable.put("lastName", "radish");
    return returnable;
}

我似乎无法弄清楚我错过了什么。我已经上传了示例代码on GitHub here

【问题讨论】:

  • 您的 POM 似乎设置不正确。有三种配置方式——编译时、后编译和运行时,看起来你可能已经配置了编译和后编译配置。我作为评论回答,因为我不想在答案中重复所有代码,但我建议查看诸如 baeldung.com/aspectj 之类的教程以获取正确的 POM 配置。
  • @GreyBeardedGeek 我正在关注同一篇文章。我从this section 复制了 pom 配置。使用编译时编织。但我无法让它工作,并且在链接到 GitHub 的示例代码中,他们使用的是Spring-AOP,因此问题

标签: java maven aspectj aspect


【解决方案1】:

您正在使用 AspectJ Maven 插件,即您将使用编译时编织。因此,您不需要 aop.xml,因为该文件用于加载时编织。所以你可以删除它。

在编译期间你应该得到一个编译错误:

Unbound pointcut parameter 'dataTrackEnabled'

这告诉你你的通知方法有一个参数dataTrackEnabled,它不会出现在切入点的任何地方,因为它应该出现。所以只需将切入点从

@Around("@annotation(com.carrot.personal.aspects.DataTrackEnabled)")

@Around("@annotation(dataTrackEnabled)")

如您所见,我指的是切入点中的方法参数名称。如果您不将注解绑定到参数,则需要使用之前使用的全限定类名。

此外,您的 Maven POM 应该会导致此错误:

diamond operator is not supported in -source 1.5

这是因为使用 AspectJ Maven 不会自动停用或替换 Maven Compiler Plugin,而后者抱怨您没有为其设置源和目标版本。所以你有两个选择:

  1. 停用 Maven 编译器,让 AspectJ Maven 编译您的 Java 和方面类。
  2. 将 Maven 编译器的编译器级别设置为 1.8(或简称为 8),并为 AspectJ Maven 使用相同的设置。

我会选择选项号。 2 在这种情况下。 Maven 知道名为maven.compiler.source and maven.compiler.target 的属性。让我们定义和使用它们:

  <!-- (...) -->

  <properties>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
  </properties>

  <!-- (...) -->

        <artifactId>aspectj-maven-plugin</artifactId>
        <version>1.7</version>
        <configuration>
          <complianceLevel>${maven.compiler.target}</complianceLevel>
          <source>${maven.compiler.source}</source>
          <target>${maven.compiler.target}</target>

  <!-- (...) -->

现在还有一些警告:

Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!

File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!

bad version number found in C:\Users\alexa\.m2\repository\org\aspectj\aspectjrt\1.8.9\aspectjrt-1.8.9.jar expected 1.8.2 found 1.8.9

前两个只是因为你忘了设置&lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;。在此过程中,您也可以为生成的报告设置编码:&lt;project.reporting.outputEncoding&gt;UTF-8&lt;/project.reporting.outputEncoding&gt;

最后一个是方面相关的,因为AspectJ Maven 1.7 depends on AspectJ 1.8.2,而不是1.8.9。但小心点!它取决于aspectjtools(用于使用编译器),而不是aspectjweaver(用于加载时编织)。您可以升级版本或覆盖插件内的依赖项。以防万一,我将同时向您展示两者。

最后但同样重要的是,AspectJ 1.8 的最新版本是 1.8.13。但是你可以只使用最新的 1.9.6 版本,它最高支持 Java 14(Java 15+16 的下一个版本几乎准备就绪)并且仍然可以为 Java 8 生成字节码。

这个 POM 怎么样?

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.carrot</groupId>
  <artifactId>SO_AJ_MavenProjectNotWorking_66734262</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
    <aspectj.version>1.9.6</aspectj.version>
  </properties>

  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
        <version>1.7</version>
        <configuration>
          <complianceLevel>${maven.compiler.target}</complianceLevel>
          <source>${maven.compiler.source}</source>
          <target>${maven.compiler.target}</target>
          <showWeaveInfo>true</showWeaveInfo>
          <verbose>true</verbose>
          <Xlint>ignore</Xlint>
          <encoding>UTF-8</encoding>
        </configuration>
        <executions>
          <execution>
            <goals>
              <!-- use this goal to weave all your main classes -->
              <goal>compile</goal>
              <!-- use this goal to weave all your test classes -->
              <goal>test-compile</goal>
            </goals>
          </execution>
        </executions>
        <dependencies>
          <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjtools</artifactId>
            <version>${aspectj.version}</version>
          </dependency>
        </dependencies>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>${aspectj.version}</version>
    </dependency>
  </dependencies>

</project>

现在,当您运行程序时,您应该会看到如下内容:

Recording: dataClass = Hey, dataName = There, instance = How are you?
Recording: dataClass = Hey, dataName = There, instance = How are you?

您可能会问为什么会触发两次建议。好吧,仅仅因为@annotation(dataTrackEnabled) 捕获了方法call() 和方法execution() 切入点。因此,让我们将匹配限制为只执行处决。

完整的解决方案如下所示(不要忘记为您的注释保留RUNTIME):

package com.carrot.personal.aspects;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface DataTrackEnabled {
  String dataClass();
  String dataName();
  String instance();
}
package com.carrot.personal.app;

public class DataTrackHelper {
  public void recordInstanceCount(String dataClass, String dataName, String instance) {
    System.out.println("Recording: dataClass = " + dataClass + ", dataName = " + dataName + ", instance = " + instance);
  }
}
package com.carrot.personal.app;

import com.carrot.personal.aspects.DataTrackEnabled;

import java.util.HashMap;
import java.util.Map;

public class Application {
  public static void main(String[] args) {
    System.out.println(new Application().fetchUser());
  }

  @DataTrackEnabled(dataClass = "Hey", dataName = "There", instance = "How are you?")
  public Map<String, String> fetchUser() {
    Map<String, String> returnable = new HashMap<>();
    returnable.put("firstName", "carrot");
    returnable.put("lastName", "radish");
    return returnable;
  }
}
package com.carrot.personal.aspects;

import com.carrot.personal.app.DataTrackHelper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class DataTrackAspect {
  @Around("@annotation(dataTrackEnabled) && execution(* *(..))")
  public Object performAspect(ProceedingJoinPoint joinPoint, DataTrackEnabled dataTrackEnabled) throws Throwable {
    System.out.println(joinPoint);
    Object result = joinPoint.proceed();
    DataTrackHelper dataTrackHelper = new DataTrackHelper();
    dataTrackHelper.recordInstanceCount(dataTrackEnabled.dataClass(), dataTrackEnabled.dataName(), dataTrackEnabled.instance());
    return result;
  }
}

我添加了更多日志输出,所以让我们再次运行应用程序:

execution(Map com.carrot.personal.app.Application.fetchUser())
Recording: dataClass = Hey, dataName = There, instance = How are you?
{firstName=carrot, lastName=radish}

【讨论】:

  • 感谢您的详细解释和修改代码(+1)。我只有两个问题:(1)&amp;&amp; execution(* *(..) 是做什么的?我在哪里可以阅读更多关于它的信息? (2) 当我在我的 IDE (Intellij) 中运行代码时,它不会触发方面,但是当我第一次运行 maven clean compile 然后在我的 IDE 中运行时,会触发方面。我应该使用不同的编织方式让它运行而不运行maven clean compile
  • (1) 你想使用 AspectJ。那么为什么不阅读 AspectJ 手册呢?简短的回答是:call() 拦截调用源,execution() 目标。想象一下从代码中的 50 个不同位置调用的方法。 call() 将编织到每个调用类中,execution() 仅编织到定义方法的类中。如需更深入的解释,请参阅my answer here。但也请阅读手册! (2) 听起来好像您没有为 IntelliJ 安装 AspectJ 扩展。
猜你喜欢
  • 1970-01-01
  • 2021-03-07
  • 1970-01-01
  • 1970-01-01
  • 2018-02-20
  • 1970-01-01
  • 1970-01-01
  • 2017-09-01
  • 1970-01-01
相关资源
最近更新 更多