Search code examples
javaspringspring-aop

Advice is not executing for custom annotation used at method level and it seems problem with poincut , any suggestions?


My advice in the following aspect is not getting executed:

package com.xxxx.logging.core.config;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogingAspectHandler {

    @Autowired
    CustomAppender lCustomAppender;

    //@Pointcut("execution(@com.xxxx.logging.core.config.CustomLogged * *(..))")
    @Pointcut("@annotation(com.xxxx.logging.core.config.CustomLogged)")
    public void customAnnotated() {}

    @Around("customAnnotated()")
    public void customLogger(ProceedingJoinPoint lProceedingJointPoint) {
        System.out.println("Get it "+lProceedingJointPoint.getSignature().getName());
        lCustomAppender.logEntryLevelInfo(lProceedingJointPoint);
          
    }
}

I have created a custom annotation named CustomLogged with Target(ElementType.METHOD) and using it at method level in a class within package com.xxxx.logging.core.config. Now I want a pointcut for all those methods which are annotated with @CustomLogged.

Please find the source code link
https://github.com/ssnarvariya/July_Projects.git


Solution

  • Thanks for the MCVE on GitHub. There are so many problems in your application, without the full project I would never have been able to find out what is wrong with it. Among other things, you have these problems:

    • Your aspect has not one, but two @Around advices. None of them proceeds to the original method. This has the effect that only the first advice gets triggered (whichever Spring AOP finds first), but never the second one. And also, your original method is never called. Therefore, both advices need to call lJoinPoint.proceed(). In @Before or @After advices, this is not necessary, but in @Around it is, hence the parameter type ProceedingJoinPoint (not a simple JoinPoint like in the other advice types).

    • Spring AOP only works on Spring-managed components or beans, but you instantiate your EVMLogger instance by simply calling a static factory method outside the control of Spring. Therefore, Spring AOP can never create an AOP proxy for this class and never intercept any method calls on it. The @CustomLogged annotation on method public void debug(Object lMsg) has no effect.

    • Also in EVMLogger, you save a Logger instance in a static variable, but actually if you want a different Logger for each class using EVMLogger, you cannot overwrite this static field. You have to make it an instance field and set it whenever you create a EVMLogger instance.

    • That you need multiple EVMLogger instances, also means that you cannot use a singleton bean but should use a prototype bean. There are several ways to instantiate a parametrised prototype bean dynamically. I am showing you how to auto-wire the application context into target class constructors needing the EVMLogger and there to get a bean instance from the context. This applies to two different classes in your example.

    One more thing that looks weird to me, is that your aspect logs what EVMLogger does, i.e. a logger loggging infos about another logger. But maybe your aspect does something else in reality and logging was just for the sake of the MCVE. I am assuming it is so.

    I created a pull request for your convenience. The key commits are:

    The console log when calling curl http://127.0.0.1:8080/getreq looks like this:

    Inside logEntryLevelInfo for method ::showSampleData
    Inside logEntryLevelInfo for method ::tryService
    {"@timestamp":"2021-07-02T19:49:54.879+07:00","@version":"1","message":"Debug Msg...","logger_name":"org.ssn.app.config.CustomLogService","thread_name":"http-nio-8080-exec-1","level":"DEBUG","level_value":10000,"app_msg":{"mthd_name":"tryService","mtd_args":["Message1"]}}
    Inside logCustomAnnotatedInfo for annotated method ::debug
    {"@timestamp":"2021-07-02T19:49:54.879+07:00","@version":"1","message":"Custom Debug Msg...","logger_name":"org.ssn.app.controller.TestController1","thread_name":"http-nio-8080-exec-1","level":"DEBUG","level_value":10000,"app_msg":From Controller---}
    {"@timestamp":"2021-07-02T19:49:54.879+07:00","@version":"1","message":"Debug Msg...","logger_name":"org.ssn.app.config.CustomLogService","thread_name":"http-nio-8080-exec-1","level":"DEBUG","level_value":10000,"app_msg":{"mthd_name":"showSampleData","mtd_args":[]}}
    

    You see that

    • there are two distinct logger names CustomLogService and TestController1 and
    • both aspect advices fire now.