Aspect не работает с загрузочным приложением Spring с внешней банкой

Я пытаюсь создать аспект таймера для измерения времени выполнения методов.

Я создал аннотацию с именем @Timer:

@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.TYPE})
public @interface Timer {
    String value();
}

И затем я создал аспект следующим образом:

@Aspect
public class MetricAspect {

    @Autowired
    private MetricsFactory metricsFactory;

    @Pointcut("@annotation(my.package.Timer)")
    public void timerPointcut() {}

    @Around("timerPointcut() ")
    public Object measure(ProceedingJoinPoint joinPoint) throws Throwable {
       /* Aspect logic here */
    }

    private Timer getClassAnnotation(MethodSignature methodSignature) {
        Timer annotation;
        Class<?> clazz = methodSignature.getDeclaringType();
        annotation = clazz.getAnnotation(Timer.class);
        return annotation;
    }

У меня есть класс конфигурации следующим образом:

@Configuration
@EnableAspectJAutoProxy
public class MetricsConfiguration {

    @Bean
    public MetricAspect notifyAspect() {
        return new MetricAspect();
    }
}

Все до тех пор, пока здесь не определено в упакованном банке, который я использую в качестве зависимостей в моем загрузочном приложении spring

В моем загрузочном приложении spring я импортирую MetricsConfiguration, и я отладил код и увидел, что создан MetricAspect bean.

Я использую его в коде следующим образом:

@Service
public class MyService {
    ...

    @Timer("mymetric")
    public void foo() {
       // Some code here...
    }

    ...
}

Но мой код не доходит до метода measure. Не уверен, что мне не хватает.

Для завершения изображения у меня есть эти зависимости в моем файле pom:

<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.7.4</version>
    </dependency>

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.7.4</version>
    </dependency>
</dependencies>

Что класс @Configuration, который импортирует MetricsConfiguration:

@Configuration
@EnableAspectJAutoProxy
@Import(MetricsConfiguration.class)
@PropertySource("classpath:application.properties")
public class ApplicationConfiguration {

}

Он загружается с загрузкой автоматической загрузки spring.

Ответ 1

может @Component или @Configurable решить вашу проблему?

@Aspect
@Component
public class yourAspect {
 ...
}

Включить Spring AOP или AspectJ

РЕДАКТИРОВАТЬ:

Я создал проект, чтобы смоделировать вашу проблему, кажется, не проблема в конце концов. Это затронуто другой проблемой?

https://github.com/zerg000000/spring-aspectj-test

Ответ 2

Я не смог воспроизвести вашу проблему, используя aspectJ 1.8.8 и spring 4.2.5. Здесь мой мультимодульный подход maven с аспектом в отдельной банке.

Я немного изменил ваш код, но не изменил аннотации. Единственное, что может отличаться, это то, что я добавил зависимость org.springframework:spring-aop и определил мою точку входа следующим образом:

@Import(MetricsConfiguration.class)
@SpringBootApplication
public class Application {
    // @Bean definitions here //

    public static void main(String[] args) throws InterruptedException {
        ApplicationContext ctx = 
            SpringApplication.run(Application.class, args);
        ctx.getBean(MyService.class).doWork();
    }
}

Ответ 3

У меня была похожая проблема, когда аспект был построен в библиотеке jar, а приложение весенней загрузки было где-то еще. Оказывается, что пакеты для приложения весенней загрузки и библиотеки jar были разными. Из-за этого Spring не изучал пакет библиотеки для автоматического подключения к контексту приложения.

Итак, пришлось включить @ComponentScan({"base.package.application.*", "base.package.library.*"}) В Application.java.

Ответ 4

  1. Если внешний jar - это Spring boot Starter, вы можете настроить Aspect bean в AutoConfiguration:

(1)

@Aspect
public class MyAspect {
  //....
}

(2)

package a.b.c

@Configuration
public class MyAutoConfiguration {
    @Bean
    MyAspect myAspect() {
        return new MyAspect();
    }   
}

(3) конфиг в spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
a.b.c.MyAutoConfiguration
  1. Если внешний jar файл не является загрузчиком Spring, просто загрузите Aspect как bean-компонент, вы можете использовать @ComponentScan

Ответ 5

Добавьте этот компонент Scan для решения проблемы.

@ComponentScan("package.of.aspect")
@Configuration
@EnableAspectJAutoProxy
@Import(MetricsConfiguration.class)
@PropertySource("classpath:application.properties")
public class ApplicationConfiguration {

}

Ответ 6

В соответствии с объяснением mojohaus, вы должны добавить настройки сборки, как показано ниже, для тканого вашего аспекта во все классы, реализующие ваш интерфейс аспекта.

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.11</version>
            <configuration>
                <complianceLevel>1.8</complianceLevel>
                <includes>
                    <include>**/*.java</include>
                    <include>**/*.aj</include>
                </includes>
                <aspectDirectory>src/main/aspect</aspectDirectory>
                <testAspectDirectory>src/test/aspect</testAspectDirectory>
                <XaddSerialVersionUID>true</XaddSerialVersionUID>
                <showWeaveInfo>true</showWeaveInfo>
                <aspectLibraries>
                    <aspectLibrary>
                        <groupId>your aspect groupId</groupId>
                        <artifactId>your aspect artifactId</artifactId>
                    </aspectLibrary>
                </aspectLibraries>
            </configuration>
            <executions>
                <execution>
                    <id>compile_with_aspectj</id>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                </execution>
                <execution>
                    <id>test-compile_with_aspectj</id>
                    <goals>
                        <goal>test-compile</goal>
                    </goals>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjtools</artifactId>
                    <version>${aspectj.runtime.version}</version>
                </dependency>
                <dependency>
                    <groupId>your aspect groupId</groupId>
                    <artifactId>youar aspect artifactId</artifactId>
                    <version>1.0.0-SNAPSHOT</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>