AspectJ:自定义 *.aj 文件被忽略 [英] AspectJ: custom *.aj file is ignored

查看:32
本文介绍了AspectJ:自定义 *.aj 文件被忽略的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么 aspectj-maven-plugin 忽略我的 AnnotationInheritor.aj 文件?我配置有问题吗?

我想用自定义注释建议 ItemRepository#getById:

@Repository公共接口 ItemRepository 扩展 JpaRepository{//AOP 不起作用,因为自动生成的 ItemRepositoryImpl#getById//不会有@MyAnnotation 注释@MyAnnotation公共项目 getById(Long id);}@目标(元素类型.方法)@Retention(RetentionPolicy.RUNTIME)@遗传公共@interface MyAnnotation {}@方面@零件公共类我的方面{@Around("@annotation(MyAnnotation)")公共对象执行(ProceedingJoinPoint joinPoint){//当@MyAnnotation 放在类上时,这个建议是正确的,我测试过.//问题是我必须把@MyAnnotation 放在接口方法上}}

Spring Data JPA 使用接口,Java 注释永远不会从接口继承到子类(由于 JVM 限制).为了使我的建议与自定义注释一起使用 有一个小小的 AspectJ 技巧.因此,如先前参考中所述,我创建了 AnnotationInheritor.aj 文件:

package com.vbakh.somepackage.aspects;//由于某种原因不起作用.为什么?公共方面 AnnotationInheritor {声明@method : void ItemRepository+.getById() : @MyAnnotation;}

并将以下配置添加到我的pom.xml:

...<依赖><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></依赖><依赖><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.8.9</version></依赖></依赖项><构建><插件><插件><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.6.0</version><配置><来源>1.8</来源><目标>1.8</目标><!-- 重要信息--><useIncrementalCompilation>false</useIncrementalCompilation></配置></插件><插件><groupId>org.codehaus.mojo</groupId><artifactId>aspectj-maven-plugin</artifactId><version>1.9</version><配置><complianceLevel>1.8</complianceLevel><来源>1.8</来源><目标>1.8</目标><showWeaveInfo>true</showWeaveInfo><详细>真</详细><Xlint>忽略</Xlint><encoding>UTF-8 </encoding></配置><执行><执行><phase>process-sources</phase><目标><目标>编译</目标></目标></执行></执行><依赖项><依赖><groupId>org.aspectj</groupId><artifactId>aspectjtools</artifactId><version>1.8.10</version></依赖></依赖项></插件></插件></build>

附言有没有办法在没有 *.aj 文件的情况下执行相同的逻辑?表示带有 *.java 文件.

解决方案

我将您的代码复制到 AspectJ 项目中(没有 Spring 或 Spring AOP),以便对其进行测试.我发现了几个问题:

  • @Around("@annotation(MyAnnotation)") 将找不到注释,因为没有完全限定的类名.

  • 声明@method : void ItemRepository+.getById() : @MyAnnotation; 与您的接口方法的签名Item getById(Long id) 不匹配.p>

  • MyAspects.execute(..) 需要抛出Throwable,当然也要返回一些东西,比如joinPoint.proceed().但也许那只是草率的复制&粘贴.

修复此问题后,以下 MCVE 运行良好:

帮助项目编译的类:

package de.scrum_master.app;公共类项目{}

package de.scrum_master.app;公共接口 JpaRepository<P, Q>{}

package de.scrum_master.app;导入 org.springframework.stereotype.Repository;@Repository公共接口 ItemRepository 扩展 JpaRepository{项目 getById(长 id);}

package de.scrum_master.app;公共类 ItemRepositoryImpl 实现 ItemRepository {@覆盖公共项目 getById(长 ID){返回新项目();}}

标记注释:

package de.scrum_master.app;导入 java.lang.annotation.*;@目标(元素类型.方法)@Retention(RetentionPolicy.RUNTIME)@遗传公共@interface MyAnnotation {}

驱动程序应用:

package de.scrum_master.app;公共类应用{公共静态无效主(字符串 [] args){ItemRepository 存储库 = new ItemRepositoryImpl();repository.getById(11L);}}

方面:

以防万一你想知道为什么我将 execution(* *(..)) 添加到切入点,这是因为我想排除匹配的 call() 连接点这些在 AspectJ 中可用,而不是在 Spring AOP 中.

package de.scrum_master.aspect;导入 org.aspectj.lang.ProceedingJoinPoint;导入 org.aspectj.lang.annotation.Around;导入 org.aspectj.lang.annotation.Aspect;导入 org.springframework.stereotype.Component;@方面@零件公共类 MyAspect {@Around("@annotation(de.scrum_master.app.MyAnnotation) && execution(* *(..))")公共对象执行(ProceedingJoinPoint joinPoint)抛出 Throwable {System.out.println(joinPoint);返回 joinPoint.proceed();}}

package de.scrum_master.aspect;导入 de.scrum_master.app.Item;导入 de.scrum_master.app.ItemRepository;导入 de.scrum_master.app.MyAnnotation;公共方面 AnnotationInheritor {声明@method : Item ItemRepository+.getById(Long) : @MyAnnotation;}

控制台日志:

执行(Item de.scrum_master.app.ItemRepositoryImpl.getById(Long))

瞧!效果很好.

如果它对您不起作用,那么您还有其他问题,例如(但不仅限于)

  • 您顺便提到的自动生成的ItemRepositoryImpl#getById".无论何时何地在构建过程中生成它,它都需要在方面应用于它之前存在.不过,为了分析这一点,我需要在 GitHub 上有一个 MCVE.

  • 织入方面的目标代码是否与方面代码在同一个Maven模块中.如果不是,您需要更改您的 Maven 设置.

Why aspectj-maven-plugin ignore my AnnotationInheritor.aj file? Am I configured something wrong?

I want to advice ItemRepository#getById with custom annotation:

@Repository
public interface ItemRepository extends JpaRepository<Item, Long> {

    // AOP does not work, since autogenerated ItemRepositoryImpl#getById 
    // won't have @MyAnnotation annotation
    @MyAnnotation 
    public Item getById(Long id);
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyAnnotation {
}

@Aspect
@Component
public class MyAspects {

    @Around("@annotation(MyAnnotation)")
    public Object execute(ProceedingJoinPoint joinPoint) {
        // This advice works correct when @MyAnnotation is placed on class, I tested. 
        // The problem is that I have to put @MyAnnotation on interface method
    }
}

Spring Data JPA use interfaces and Java annotations are never inherited from interface to subclass (due JVM limitations). To make my advice work with custom annotations there is a little AspectJ trick. So as described at previous referrence, I created AnnotationInheritor.aj file:

package com.vbakh.somepackage.aspects;

// For some reason does not work. WHY?
public aspect AnnotationInheritor { 
    declare @method : void ItemRepository+.getById() : @MyAnnotation;
}

And add the following configurations to my pom.xml:

<dependencies>
    ...
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

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

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.6.0</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <!-- IMPORTANT -->
                <useIncrementalCompilation>false</useIncrementalCompilation>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.9</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>
                    <phase>process-sources</phase>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjtools</artifactId>
                    <version>1.8.10</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

P.S. Is there any way to perform the same logic without *.aj files? Means with *.java files.

解决方案

I copied your code into an AspectJ project (no Spring or Spring AOP there) in order to test it. I found a few problems:

  • @Around("@annotation(MyAnnotation)") will not find the annotation because there is no fully qualified class name.

  • declare @method : void ItemRepository+.getById() : @MyAnnotation; does not match your interface method's signature Item getById(Long id).

  • MyAspects.execute(..) needs to throw Throwable and of course also return something, such as the result of joinPoint.proceed(). But maybe that was just sloppy copy & paste.

After fixing this, the following MCVE works beautifully:

Helper classes making the project compile:

package de.scrum_master.app;

public class Item {}

package de.scrum_master.app;

public interface JpaRepository<P, Q> {}

package de.scrum_master.app;

import org.springframework.stereotype.Repository;

@Repository
public interface ItemRepository extends JpaRepository<Item, Long> {
  Item getById(Long id);
}

package de.scrum_master.app;

public class ItemRepositoryImpl implements ItemRepository {
  @Override
  public Item getById(Long id) {
    return new Item();
  }
}

Marker annotation:

package de.scrum_master.app;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyAnnotation {}

Driver Application:

package de.scrum_master.app;

public class Application {
  public static void main(String[] args) {
    ItemRepository repository = new ItemRepositoryImpl();
    repository.getById(11L);
  }
}

Aspects:

Just in case you wonder why I added execution(* *(..)) to the pointcut, this is because I wanted to exclude matching call() joinpoints which are available in AspectJ as opposed to Spring AOP.

package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyAspect {
  @Around("@annotation(de.scrum_master.app.MyAnnotation) && execution(* *(..))")
  public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println(joinPoint);
    return joinPoint.proceed();
  }
}

package de.scrum_master.aspect;

import de.scrum_master.app.Item;
import de.scrum_master.app.ItemRepository;
import de.scrum_master.app.MyAnnotation;

public aspect AnnotationInheritor {
  declare @method : Item ItemRepository+.getById(Long) : @MyAnnotation;
}

Console log:

execution(Item de.scrum_master.app.ItemRepositoryImpl.getById(Long))

Voilà! It works nicely.

If it does not work for you like this you have other issues such as (but not exclusively)

  • the "auto-generated ItemRepositoryImpl#getById" you mentioned in passing. Whenever and wherever this is generated during the build process, it needs to exist before the aspect is applied to it. In order to analyze this I would need an MCVE on GitHub, though.

  • whether the target code to weave the aspect into is in the same Maven module as the aspect code. If it is not, you need to change your Maven setup.

这篇关于AspectJ:自定义 *.aj 文件被忽略的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆