为什么aspectj-maven-plugin
会忽略我的AnnotationInheritor.aj
文件?我配置错了吗?
我想建议使用自定义注释ItemRepository#getById
:
@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使用接口和Java注释永远不会从接口继承到子类(由于JVM限制)。使我的建议适用于自定义注释there is a little AspectJ trick。因此,如前面所述,我创建了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
:
<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。 有没有办法在没有* .aj文件的情况下执行相同的逻辑?含有* .java文件的方法。
答案 0 :(得分:1)
我将你的代码复制到一个AspectJ项目(没有Spring或Spring AOP)以便测试它。我发现了一些问题:
@Around("@annotation(MyAnnotation)")
找不到注释,因为没有完全限定的类名。
declare @method : void ItemRepository+.getById() : @MyAnnotation;
与您的界面方法的签名Item getById(Long id)
不符。
MyAspects.execute(..)
需要抛出Throwable
,当然也会返回一些内容,例如joinPoint.proceed()
的结果。但也许那只是草率的副本&amp;糊。
修好后,以下MCVE可以很好地运作:
帮助项目编译项目:
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();
}
}
标记注释:
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设置。
答案 1 :(得分:0)