samshers
samshers

Reputation: 3690

Spring AOP not working in main class with Spring Boot Project?

I am trying to use spring aop in a spring boot project. I am not sure why I am not getting the advice weaved at the join point in main class. AOP is working well in a service class. The code is as below.

SpringBootWithAOP.java

package com.example.demo;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.example.demo.services.SayHelloService;

@SpringBootApplication
public class SpringBootWithAOP {

    @Autowired
    SayHelloService service;

    String message;
    static String name;

    public static void main(String[] args) {
        name="George";
        SpringApplication.run(SpringBootWithAOP.class, args);
    }

    @PostConstruct
    public void init() {
        service.message(name);
    }
}

SayHelloService.java

package com.example.demo.services;
import org.springframework.stereotype.Service;

@Service
public class SayHelloService {
    public String message(String name) {
        System.out.println("Hello Dear User - " + name );
        return "Hello Dear User - " + name ;
    }
}

MasterLoggerAspect.java

package com.example.demo.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MasterLoggerAspect {
    @Before("execution(* com.example.demo.services.*.*(..) )")
    public void doForEveryServicesMethod(JoinPoint jp){
        System.out.println("hurray! In class: " + jp.getSignature().getDeclaringTypeName() + " - before method: " + jp.getSignature().getName());
    }
    //this advice is not getting weaved
    @Before("execution(* com.example.demo.*.*(..)) " )
    public void doForEveryMainClassMethod(JoinPoint jp){
        System.out.println("hurray! In class: " + jp.getClass() + " - before method: " + jp.getSignature().getName());
    }
}

pom.xml has spring-boot-starter-aop in the dependencies.

Could some one suggest where the problem exists.

Output -

hurray! In class: com.example.demo.services.SayHelloService - before method: message
Hello Dear User - George

Code available here: https://github.com/samshers/46692518/

Upvotes: 0

Views: 4535

Answers (2)

Indra Basak
Indra Basak

Reputation: 7394

You need to use two dots notation (..) after service package to include sub-packages. Once you start using * com.example.demo..*.*(..), all Spring managed beans will be logged except main and the method tagged with @PostConstruct. According to PostConstruct JavaDoc, this method MUST be invoked before the class is put into service.

@Component
@Aspect
public class MasterLoggerAspect {

    @Pointcut("execution(* com.example.demo..*.*(..))")
    public void logForAllMethods(){}

    @Before("execution(* com.example.demo.services.*.*(..) )")
    public void doForEveryServicesMethod(JoinPoint jp){
        System.out.println("hurray! In class: " + jp.getSignature().getDeclaringTypeName() + " - before method: " + jp.getSignature().getName());
    }

    @Before("execution(* com.example.demo..*.*(..) )" )
    public void doForEveryMainClassMethod(JoinPoint jp){
        System.out.println("hurray! In class: " + jp.getClass() + " - before method: " + jp.getSignature().getName());
    }
}

If you add @Component annotation to the Spring Boot main class and autowire it to another class, then any method invoked in SpringBootWithAOP class will be logged. For example,

@SpringBootApplication
@Component
public class SpringBootWithAOP {

    @Autowired
    SayHelloService service;

    String message;
    static String name;

    public static void main(String[] args) {
        name="George";
        SpringApplication.run(SpringBootWithAOP.class, args);
    }

    public void sayHello() {
        System.out.println("888888");
    }

    @PostConstruct
    public void init() {
        service.message(name);
    }
}

Changes to SayHelloService class,

@Service
public class SayHelloService {

    @Autowired
    SpringBootWithAOP aop;

    public String message(String name) {
        System.out.println("Hello Dear User - " + name );
        aop.sayHello();
        return "Hello Dear User - " + name ;
    }
}

Here are the logged messages,

hurray! In class: class org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint - before method: message
hurray! In class: com.example.demo.services.SayHelloService - before method: message
Hello Dear User - George
hurray! In class: class org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint - before method: sayHello
888888

Upvotes: 3

LT56
LT56

Reputation: 187

"Spring AOP currently supports only method execution join points (advising the execution of methods on Spring beans)."

I do not believe the application Entrypoint is a bean.

Look at CommandLineRunner interface and implementing your own class that overrides run.The Command Line Runner will run as soon as the beans are initialized.

Upvotes: 0

Related Questions