有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

JavaAspectJ:custom*。忽略aj文件

为什么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数据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>

另外,有没有办法在没有*的情况下执行相同的逻辑。aj文件?意思是带*。java文件


共 (2) 个答案

  1. # 1 楼答案

    我想即使没有AnnotationInheritor,它也应该能工作

    制作了一个小演示,看看

    demo

  2. # 2 楼答案

    我将您的代码复制到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<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设置