복붙노트

[SPRING] AspectJ : 사용자 정의 * .aj 파일이 무시됩니다.

SPRING

AspectJ : 사용자 정의 * .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
    }
}

스프링 데이터 JPA 사용 인터페이스 및 Java 주석은 인터페이스에서 하위 클래스로 상속되지 않습니다 (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에 추가하십시오.

<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 파일을 사용합니다.

해결법

  1. ==============================

    1.테스트하기 위해 코드를 AspectJ 프로젝트에 복사했다 (스프링 또는 AOP가 없다). 나는 약간 문제를 찾아 냈다 :

    테스트하기 위해 코드를 AspectJ 프로젝트에 복사했다 (스프링 또는 AOP가 없다). 나는 약간 문제를 찾아 냈다 :

    이 문제를 해결 한 후 다음 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);
      }
    }
    

    상들:

    (* * (..))을 Pointcut에 추가 한 이유가 궁금한 경우, AspectJ에서 Spring AOP와는 반대로 사용할 수있는 joinpoint를 제외하고자했기 때문이다.

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

    Voilà! 그것은 잘 작동합니다.

    만약 당신이 이것을 좋아하지 않는다면 다른 문제가 있습니다.

  2. ==============================

    2.AnnotationInheritor가 없어도 작동해야합니다.

    AnnotationInheritor가 없어도 작동해야합니다.

    작은 데모를 만들었습니다.

    데모

  3. from https://stackoverflow.com/questions/50391609/aspectj-custom-aj-file-is-ignored by cc-by-sa and MIT license