简体   繁体   English

在 Maven 项目中未触发 AspectJ 方面

[英]AspectJ Aspects not getting triggered in Maven Project

I am trying to build a POC project using AspectJ without using Spring AOP .我正在尝试使用AspectJ构建 POC 项目而不使用Spring AOP I am using an annotation based approach where I want to run the aspect @Around the method which has been annotated with an annotation.我正在使用基于注释的方法,我想在其中运行方面@Around已使用注释进行注释的方法。 For some reason my aspects don't get triggered.出于某种原因,我的方面没有被触发。 Below is my code:下面是我的代码:

pom.xml 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>

resources/META-INF/aop.xml资源/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>

My Aspect:我的观点:

@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;
    }
}

The annotated method带注释的方法

@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;
}

I can't seem to figure it out as to what am I missing.我似乎无法弄清楚我错过了什么。 I have uploaded the sample code on GitHub here .在这里上传了 GitHub 上的示例代码。

You are using AspectJ Maven Plugin, ie you are going to use compile-time weaving.您正在使用 AspectJ Maven 插件,即您将使用编译时编织。 Therefore, you do not need aop.xml because that one is used for load-time weaving.因此,您不需要 aop.xml,因为它用于加载时编织。 So you can delete it.所以你可以删除它。

During compilation you should get a compile error:在编译期间,您应该得到一个编译错误:

Unbound pointcut parameter 'dataTrackEnabled'

That tells you that your advice method has a parameter dataTrackEnabled which does not occur anywhere in the pointcut as it should.这告诉您您的通知方法有一个参数dataTrackEnabled ,它不会出现在切入点的任何地方,因为它应该出现。 So just change the pointcut from所以只需将切入点从

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

to

@Around("@annotation(dataTrackEnabled)")

As you see, I am referring to the method parameter name from the pointcut.如您所见,我指的是切入点中的方法参数名称。 If you would not bind the annotation to a parameter, then you would need the fully qualified class name as you used it before.如果您不将注释绑定到参数,那么您将需要之前使用的完全限定的 class 名称。

Also, your Maven POM should cause this error:此外,您的 Maven POM 应该会导致此错误:

diamond operator is not supported in -source 1.5

This is because using AspectJ Maven does not automatically deactivate or replace Maven Compiler Plugin and the latter complains that you did not set source and target versions for it.这是因为使用 AspectJ Maven 不会自动停用或替换 Maven 编译器插件,后者抱怨您没有为其设置源和目标版本。 So you have two options:所以你有两个选择:

  1. Deactivate Maven Compiler, let AspectJ Maven compile your Java and aspect classes.停用 Maven 编译器,让 AspectJ Maven 编译您的 Java 和方面类。
  2. Set the compiler level to 1.8 (or simply 8) for Maven Compiler and use the same settings for AspectJ Maven.将 Maven 编译器的编译器级别设置为 1.8(或简称为 8),并为 AspectJ Maven 使用相同的设置。

I will choose option no.我会选择选项号。 2 in this case. 2 在这种情况下。 Maven knows properties named maven.compiler.source and maven.compiler.target . Maven 知道名为maven.compiler.sourcemaven.compiler.target的属性。 Let us define and use them:让我们定义和使用它们:

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

  <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>

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

Now there are a few more warnings:现在还有一些警告:

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

The first two are just because you forgot to set <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> .前两个只是因为您忘记设置<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> While you are at it, you can set the encoding for generated reports, too: <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> .当您使用它时,您也可以为生成的报告设置编码: <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

The last one is aspect-related and due to the fact that AspectJ Maven 1.7 depends on AspectJ 1.8.2 , not 1.8.9.最后一个与方面相关,因为AspectJ Maven 1.7 取决于 AspectJ 1.8.2 ,而不是 1.8.9。 But be careful!但小心点! It depends on aspectjtools (for using the compiler), not on aspectjweaver (for load-time weaving).它依赖于aspectjtools (用于使用编译器),而不是aspectjweaver (用于加载时编织)。 You can either upgrade the version or override the dependency inside the plugin.您可以升级版本或覆盖插件内的依赖项。 I am going to show you both at the same time, just in case.为了以防万一,我将同时向你们展示两者。

Last but not least, the latest version of AspectJ 1.8 is 1.8.13.最后但同样重要的是,AspectJ 1.8 的最新版本是 1.8.13。 But you can just use the very latest version 1.9.6, it supports up to Java 14 (the next version for Java 15+16 is almost ready) and can still produce byte code for Java 8.但是您可以只使用最新版本 1.9.6,它支持高达 Java 14(Java 15+16 的下一个版本几乎准备就绪)并且仍然可以生成 ZD52187878D8759EA22 的字节码。

How about this POM?这个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>

Now when you run the program, you should see something like:现在,当您运行程序时,您应该会看到如下内容:

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

You may ask why the advice is triggered twice.您可能会问为什么会触发两次建议。 Well, just because @annotation(dataTrackEnabled) captures both the method call() and the method execution() pointcut.好吧,仅仅因为@annotation(dataTrackEnabled)捕获了方法call()和方法execution()切入点。 So let us limit the match to just executions.因此,让我们将匹配限制为仅处决。

The full solution looks like this (do not forget RUNTIME retention for your annotation):完整的解决方案如下所示(不要忘记注释的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;
  }
}

I added some more log output, so let us run the application again:我添加了更多日志 output,所以让我们再次运行应用程序:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM