AspectJ: пользовательский * .aj файл игнорируется - PullRequest
0 голосов
/ 17 мая 2018

Почему 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).Чтобы мой совет работал с пользовательскими аннотациями , есть небольшой трюк 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>

PS Есть лиспособ выполнить ту же логику без файлов * .aj?Средства с * .java файлами.

Ответы [ 2 ]

0 голосов
/ 19 мая 2018

Я скопировал ваш код в проект 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(* *(..)) к pointcut, это потому, что я хотел исключить совпадающие call() точек соединения, которые доступны в AspectJ, а не 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", который вы упомянули мимоходом. Когда бы и где бы он ни создавался в процессе сборки, он должен существовать до того, как к нему будет применен аспект. Для анализа мне понадобится MCVE на GitHub, хотя.

  • находится ли целевой код для включения аспекта в том же модуле Maven, что и код аспекта. Если это не так, вам нужно изменить настройки Maven.

0 голосов
/ 17 мая 2018

Я думаю, это должно работать, даже без AnnotationInheritor

сделал небольшое демо, посмотри ...

демо

...