Aspect does not work with Spring boot application with external jar

20,527

Solution 1

can @Component or @Configurable solve your issue?

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

Enable Spring AOP or AspectJ

EDIT:

I created a project to simulate your issue, seems no problem after all. Is it affected by other issue?

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

Solution 2

I was unable to reproduce your problem using aspectJ 1.8.8 and spring 4.2.5. Here is my maven multi-module approach with aspect in separate jar.

I modified your code slightly but did not change any annotations. The only thing that might be differ is that I've added org.springframework:spring-aop dependency and defined my entrypoint as follows:

@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();
    }
}

Solution 3

I had a similar problem where the aspect was built in a jar library, and the spring-boot application was else where. Turns out that the packages for the spring-boot application and the jar library were different. Due to which Spring was not looking into the package of the library to autowire into the application context.

So, had to include @ComponentScan({"base.package.application.*", "base.package.library.*"}) in the Application.java

Solution 4

  1. If the external jar is Spring boot starter, you can config Aspect bean in AutoConfiguration:

(1)

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

(2)

package a.b.c

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

(3)config in spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
a.b.c.MyAutoConfiguration
  1. If the external jar is not a Spring boot starter, just load Aspect as a bean, you can use @ComponentScan
Share:
20,527

Related videos on Youtube

Avi
Author by

Avi

Updated on July 09, 2022

Comments

  • Avi
    Avi almost 2 years

    I am trying to create a timer aspect for measuring methods run time.

    I created an annotation named @Timer:

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

    And then I created the aspect as follows:

    @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;
        }
    

    I have a configuration class as follows:

    @Configuration
    @EnableAspectJAutoProxy
    public class MetricsConfiguration {
    
        @Bean
        public MetricAspect notifyAspect() {
            return new MetricAspect();
        }
    }
    

    Everything up until here is defined in a packaged jar which I use as a dependency in my spring boot application

    In my spring boot application I import the MetricsConfiguration and I debugged the code and saw that the MetricAspect bean is created.

    I use it in code as follows:

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

    But my code doesn't reach to the measure method. Not sure what I'm missing.

    For completing the picture, I have these dependencies in my pom file added:

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

    That's the @Configuration class that imports MetricsConfiguration:

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

    It's loaded with Spring's automagically configuration loading.

    • Harshil Sharma
      Harshil Sharma over 7 years
      Do you also have spring-aspects dependency?
    • Avi
      Avi over 7 years
      I tried adding it and it didn't work as well :/
    • sheltem
      sheltem over 7 years
      Why are you using reflection to get the annotation? You can simply add it to the parameters of the around advice method and access it directly.
    • Avi
      Avi over 7 years
      @kriegaex - I actually created this kind of code in the past many times and it worked. The main difference is the use of spring boot which I mentioned :/
    • Viswanath Lekshmanan
      Viswanath Lekshmanan over 7 years
      Is timerPointcut() method gets invoked ?
    • Alex
      Alex about 5 years
      Hi @Avi! How did you fix this problem? I just have the same issue in my project. Thank you!
    • Avi
      Avi about 5 years
      @Alex - Unfortunately, I didn't :(
  • ka yu Lai
    ka yu Lai over 7 years
    github.com/spring-projects/spring-boot/tree/master/… official example of how to use AspectJ in spring boot
  • Avi
    Avi over 7 years
    Thanks for your answer Albert. It's not the @Component issue though. I tried for the gist of it but I create the bean in MetricsConfiguration anyway. It's not the issue. I suspect that's because the aspect and the bean are in an external jar and I'm using spring boot.
  • Avi
    Avi over 7 years
    Thanks for your thorough answer. I still couldn't find no difference between my code and yours. My guess is that it's related to the fact that spring loads a @Configuration class (actually more than one) automagically and something there gets lost. I will keep digging.
  • vsminkov
    vsminkov over 7 years
    @Avi could you show how do you import MetricsConfiguration in your application? Is it differs from my example?
  • vsminkov
    vsminkov over 7 years
    @Avi well... it seems the same for me :) can you reproduce your problem with small amount of code and post it go github?
  • Aimal Khan
    Aimal Khan almost 6 years
    adding @Component annotation solves the problem and it does makes sense as well cuz the aspect might need to be injected at runtime, any thoughts?