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
- Если внешний 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
- Если внешний 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>