AspectJ advice does not fire in Maven multi-module setup

﹥>﹥吖頭↗ 提交于 2020-01-02 07:17:09

问题


I'm trying to do AOP with Aspectj, but I don't know why is not executing my aspect, it just runs the main class. Is the first time I do this, so I might be doing something wrong.

This is my code:

The Aspect:

@Aspect
public class YourAspect {

    @Pointcut("@annotation(yourAnnotationVariableName)")
    public void annotationPointCutDefinition(YourAnnotation yourAnnotationVariableName){
    }

    @Pointcut("execution(* *(..))")
    public void atExecution(){}

    @Around("annotationPointCutDefinition(yourAnnotationVariableName) && atExecution()")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint, YourAnnotation yourAnnotationVariableName) throws Throwable {
        if(yourAnnotationVariableName.isRun()) {
            Object returnObject = null;

            try {
                System.out.println("aspects.YourAspect's aroundAdvice's body is now executed Before yourMethodAround is called.");
                returnObject = joinPoint.proceed();
            } catch (Throwable throwable) {
                throw throwable;
            } finally {
                System.out.println("aspects.YourAspect's aroundAdvice's body is now executed After yourMethodAround is called.");
            }
            return returnObject;
        }
        return joinPoint.proceed();
    }

    @After("annotationPointCutDefinition(yourAnnotationVariableName) && atExecution()")
    public void printNewLine(JoinPoint pointcut, YourAnnotation yourAnnotationVariableName){
        System.out.print("End\n\r");
    }
}

The annotation:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface YourAnnotation {
    public boolean isRun() default true;
}

The Main class:

public class MainClass{
    public static void main(String[] args) {
        MainClass yourClass = new MainClass ();
        yourClass.yourMethodAround();
    }

    @YourAnnotation
    public void yourMethodAround(){
        System.out.println("Executing TestTarget.yourMethodAround()");
    }
}

I'm working with two modules, and the POMs looks like this:

Aspect's 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>Group</groupId>
        <artifactId>Aspects</artifactId>
        <version>1.0-SNAPSHOT</version>

        <build>
            <plugins>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>aspectj-maven-plugin</artifactId>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                </plugin>
            </plugins>
        </build>

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

    </project>

Main 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>Group</groupId>
    <artifactId>Main</artifactId>
    <version>1.0-SNAPSHOT</version>

    <build>
        <pluginManagement>
            <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>
                        <aspectLibraries>
                            <aspectLibrary>
                                <groupId>Group</groupId>
                                <artifactId>Aspects</artifactId>
                            </aspectLibrary>
                        </aspectLibraries>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>compile</goal>
                                <goal>test-compile</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <version>2.5.5</version>
                    <configuration>
                        <appendAssemblyId>false</appendAssemblyId>
                        <descriptorRefs>
                            <descriptorRef>jar-with-dependencies</descriptorRef>
                        </descriptorRefs>
                        <archive>
                            <manifest>
                                <mainClass>aspects.MainClass</mainClass>
                            </manifest>
                        </archive>
                    </configuration>
                    <executions>
                        <execution>
                            <id>a-make-assembly</id>
                            <phase>package</phase>
                            <goals>
                                <goal>single</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <mainClass>aspects.MainClass</mainClass>
                </configuration>
            </plugin>
         </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>Group</groupId>
            <artifactId>Aspects</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

I did mvn clean install in both projects and then mvn exec:java in the Main project, and it just runs the method, not the aspects. Can anyone help me?

Thank you!


回答1:


Here is a multi-module solution.

Main POM (parent for all others):

Here we define all plugins with basic configuration (more specific configuration can be found in "application" module) and manage all dependency versions.

<?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>de.scrum-master.stackoverflow</groupId>
  <artifactId>main</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.source-target.version>1.8</java.source-target.version>
    <aspectj.version>1.8.10</aspectj.version>
  </properties>

  <build>
    <pluginManagement>
      <plugins>

        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.6.1</version>
          <configuration>
            <source>${java.source-target.version}</source>
            <target>${java.source-target.version}</target>
            <!-- IMPORTANT -->
            <useIncrementalCompilation>false</useIncrementalCompilation>
          </configuration>
        </plugin>

        <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>aspectj-maven-plugin</artifactId>
          <version>1.10</version>
          <configuration>
            <!--<showWeaveInfo>true</showWeaveInfo> -->
            <source>${java.source-target.version}</source>
            <target>${java.source-target.version}</target>
            <Xlint>ignore</Xlint>
            <complianceLevel>${java.source-target.version}</complianceLevel>
            <encoding>${project.build.sourceEncoding}</encoding>
            <!--<verbose>true</verbose> -->
            <!--<warn>constructorName,packageDefaultMethod,deprecation,maskedCatchBlocks,unusedLocals,unusedArguments,unusedImport</warn> -->
          </configuration>
          <executions>
            <execution>
              <!-- IMPORTANT -->
              <phase>process-sources</phase>
              <goals>
                <goal>compile</goal>
                <goal>test-compile</goal>
              </goals>
            </execution>
          </executions>
          <dependencies>
            <dependency>
              <groupId>org.aspectj</groupId>
              <artifactId>aspectjtools</artifactId>
              <version>${aspectj.version}</version>
            </dependency>
            <dependency>
              <groupId>org.aspectj</groupId>
              <artifactId>aspectjweaver</artifactId>
              <version>${aspectj.version}</version>
            </dependency>
          </dependencies>
        </plugin>

        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-assembly-plugin</artifactId>
          <version>2.5.5</version>
          <configuration>
            <appendAssemblyId>false</appendAssemblyId>
            <descriptorRefs>
              <descriptorRef>jar-with-dependencies</descriptorRef>
            </descriptorRefs>
          </configuration>
          <executions>
            <execution>
              <id>a-make-assembly</id>
              <phase>package</phase>
              <goals>
                <goal>single</goal>
              </goals>
            </execution>
          </executions>
        </plugin>

        <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>exec-maven-plugin</artifactId>
          <version>1.5.0</version>
        </plugin>

      </plugins>
    </pluginManagement>

  </build>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>${aspectj.version}</version>
      </dependency>
      <dependency>
        <groupId>de.scrum-master.stackoverflow</groupId>
        <artifactId>common</artifactId>
        <version>1.0-SNAPSHOT</version>
      </dependency>
      <dependency>
        <groupId>de.scrum-master.stackoverflow</groupId>
        <artifactId>aspect</artifactId>
        <version>1.0-SNAPSHOT</version>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <modules>
    <module>common</module>
    <module>application</module>
    <module>aspect</module>
  </modules>

</project>

Module "common":

This module contains code used by both "application" and "aspect", more specifically in this case the annotation class.

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

  <parent>
    <groupId>de.scrum-master.stackoverflow</groupId>
    <artifactId>main</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>

  <artifactId>common</artifactId>

</project>
package de.scrum_master.common;

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface YourAnnotation {
  boolean isRun() default true;
}

Module "aspect":

Here we just have the aspect code.

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

  <parent>
    <groupId>de.scrum-master.stackoverflow</groupId>
    <artifactId>main</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>

  <artifactId>aspect</artifactId>

  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
    </dependency>
    <dependency>
      <groupId>de.scrum-master.stackoverflow</groupId>
      <artifactId>common</artifactId>
    </dependency>
  </dependencies>

</project>
package de.scrum_master.aspect;

import de.scrum_master.common.YourAnnotation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class YourAspect {
  @Pointcut("@annotation(yourAnnotationVariableName)")
  public void annotationPointCutDefinition(YourAnnotation yourAnnotationVariableName) {
  }

  @Pointcut("execution(* *(..))")
  public void atExecution() {
  }

  @Around("annotationPointCutDefinition(yourAnnotationVariableName) && atExecution()")
  public Object aroundAdvice(ProceedingJoinPoint thisJoinPoint, YourAnnotation yourAnnotationVariableName) throws Throwable {
    if (yourAnnotationVariableName.isRun()) {
      Object result;
      try {
        System.out.println("Before " + thisJoinPoint);
        result = thisJoinPoint.proceed();
      } catch (Throwable t) {
        throw t;
      } finally {
        System.out.println("After " + thisJoinPoint);
      }
      return result;
    }
    return thisJoinPoint.proceed();
  }
}

Module "application":

This module contains the application code. It configures both the Exec Maven and Maven Assembly plugins. Furthermore is defines the "aspect" module as an aspect library for AspectJ Maven.

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

  <parent>
    <groupId>de.scrum-master.stackoverflow</groupId>
    <artifactId>main</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>

  <artifactId>application</artifactId>

  <build>
    <plugins>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <archive>
            <manifest>
              <addClasspath>true</addClasspath>
              <mainClass>de.scrum_master.app.MainClass</mainClass>
            </manifest>
          </archive>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <configuration>
          <mainClass>de.scrum_master.app.MainClass</mainClass>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
        <configuration>
          <aspectLibraries>
            <aspectLibrary>
              <groupId>de.scrum-master.stackoverflow</groupId>
              <artifactId>aspect</artifactId>
            </aspectLibrary>
          </aspectLibraries>
        </configuration>
      </plugin>

    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>de.scrum-master.stackoverflow</groupId>
      <artifactId>common</artifactId>
    </dependency>
    <dependency>
      <groupId>de.scrum-master.stackoverflow</groupId>
      <artifactId>aspect</artifactId>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
    </dependency>
  </dependencies>
</project>
package de.scrum_master.app;

import de.scrum_master.common.YourAnnotation;

public class MainClass {
  public static void main(String[] args) {
    MainClass yourClass = new MainClass();
    yourClass.yourMethodAround();
  }

  @YourAnnotation
  public void yourMethodAround() {
    System.out.println("Executing TestTarget.yourMethodAround()");
  }
}

Build log:

Alexander@Xander-PC MINGW64 ~/Documents/java-src/SO_AJ_MavenMultiModuleProblem
$ mvn clean install

(...)
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] main ............................................... SUCCESS [  0.241 s]
[INFO] common ............................................. SUCCESS [  0.970 s]
[INFO] aspect ............................................. SUCCESS [  1.058 s]
[INFO] application ........................................ SUCCESS [  0.607 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.111 s
[INFO] Finished at: 2017-04-07T17:15:39+02:00
[INFO] Final Memory: 23M/378M
[INFO] ------------------------------------------------------------------------

Run log:

Alexander@Xander-PC MINGW64 ~/Documents/java-src/SO_AJ_MavenMultiModuleProblem
$ cd application/

Alexander@Xander-PC MINGW64 ~/Documents/java-src/SO_AJ_MavenMultiModuleProblem/application
$ mvn exec:java
(...)
[INFO] ------------------------------------------------------------------------
[INFO] Building application 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- exec-maven-plugin:1.5.0:java (default-cli) @ application ---
Before execution(void de.scrum_master.app.MainClass.yourMethodAround())
Executing TestTarget.yourMethodAround()
After execution(void de.scrum_master.app.MainClass.yourMethodAround())
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
(...)

Alexander@Xander-PC MINGW64 ~/Documents/java-src/SO_AJ_MavenMultiModuleProblem/application
$ java -jar target/application-1.0-SNAPSHOT.jar
Before execution(void de.scrum_master.app.MainClass.yourMethodAround())
Executing TestTarget.yourMethodAround()
After execution(void de.scrum_master.app.MainClass.yourMethodAround())

Update: I pushed the whole sample project to a GitHub repository.




回答2:


OK here you go. I didn't split up things in different projects/packages to keep it as simple as possible.

Project pom.xml:

<?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>Group</groupId>
    <artifactId>Main</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.10</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>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>yourpackage.AspectJRawTest</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

        </plugins>

    </build>
</project>

Annotation (you wrote this one correctly):

package yourpackage;

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyCustomAnnotation {
    public boolean isRun() default true;
}

Custom advice which will be run before annotated methods. I am not sure about this one, terminology is not absolutely clear to me... but it seems to work :)

package yourpackage;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class MyCustomAspect {
    @Before("execution(* *.*(..)) && @annotation(MyCustomAnnotation)")
    public void advice(JoinPoint joinPoint) {
        System.out.printf("BINGO! advice() called before '%s'%n", joinPoint);
    }
}

Lastly, the main class:

package yourpackage;

public class AspectJRawTest {

    public static void main(String[] args) {
        System.out.println("custom annotation playground");

        ISomething something = new SomethingImpl();

        something.annotatedMethod();
        something.notAnnotatedMethod();
    }

}

interface ISomething {
    void annotatedMethod();

    void notAnnotatedMethod();
}

class SomethingImpl implements ISomething {
    @MyCustomAnnotation
    public void annotatedMethod() {
        System.out.println("I am annotated and something must be printed by an advice above.");
    }

    public void notAnnotatedMethod() {
        System.out.println("I am not annotated and I will not get any special treatment.");
    }
}

I build it with maven like this: mvn clean compile assembly:single to create an executable jar with dependencies included. Then, execute:

java -jar target/Main-1.0-SNAPSHOT-jar-with-dependencies.jar
custom annotation playground
BINGO! advice() called before 'execution(void yourpackage.SomethingImpl.annotatedMethod())'
I am annotated and something must be printed by an advice above.
I am not annotated and I will not get any special treatment.

I will upload a full project somewhere later and provide a link for you, but what I've posted should be sufficient.

I've tested this in IDEA and I couldn't configure it to do proper weaving for me (name any other IDE, you'll get the same problem). But I have no time for this right now, you will have to deal with that task by yourself. Good news, it must be possible since everything works with bare-bone maven.



来源:https://stackoverflow.com/questions/43260618/aspectj-advice-does-not-fire-in-maven-multi-module-setup

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!