AspectJ:忽略自定义* .aj文件

为什么aspectj-maven-plugin会忽略我的AnnotationInheritor.aj文件? 我配置错了吗?

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

 @Repository public interface ItemRepository extends JpaRepository { // 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使用接口和Java注释永远不会从接口inheritance到子类(由于JVM限制)。 为了使我的建议与自定义注释一起使用, 有一点AspectJ技巧 。 因此,如前所述,我创建了AnnotationInheritor.aj文件:

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

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

  ...  org.springframework.boot spring-boot-starter-aop   org.aspectj aspectjrt 1.8.9      org.apache.maven.plugins maven-compiler-plugin 3.6.0  1.8 1.8  false    org.codehaus.mojo aspectj-maven-plugin 1.9  1.8 1.8 1.8 true true ignore UTF-8     process-sources  compile      org.aspectj aspectjtools 1.8.10      

PS 有没有办法在没有* .aj文件的情况下执行相同的逻辑? 含有* .java文件的方法。

我将你的代码复制到一个AspectJ项目(没有Spring或Spring AOP)以便测试它。 我发现了一些问题:

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

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

  • MyAspects.execute(..)需要抛出Throwable ,当然还会返回一些内容,例如joinPoint.proceed()的结果。 但也许这只是草率的复制和粘贴。

解决此问题后,以下MCVE可以很好地工作:

使项目编译的助手类:

 package de.scrum_master.app; public class Item {} 
 package de.scrum_master.app; public interface JpaRepository {} 
 package de.scrum_master.app; import org.springframework.stereotype.Repository; @Repository public interface ItemRepository extends JpaRepository { Item getById(Long id); } 
 package de.scrum_master.app; public class ItemRepositoryImpl implements ItemRepository { @Override public Item getById(Long id) { return new Item(); } } 

标记注释:

 package de.scrum_master.app; import java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface MyAnnotation {} 

司机申请:

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

方面:

如果你想知道为什么我将execution(* *(..))到切入点,这是因为我想排除AspectJ中可用的匹配call()连接点而不是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; } 

控制台日志:

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

瞧! 它工作得很好。

如果它对你不起作用,你有其他问题,如(但不是唯一的)

  • 你提到的“自动生成的ItemRepositoryImpl#getById ”。 无论何时何地在构建过程中生成它,都需要在将方面应用于它之前存在。 为了分析这一点,我需要在GitHub上使用MCVE 。

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

我想它应该可以工作,即使没有AnnotationInheritor

做了一个小演示,看看……

演示