简体   繁体   中英

Spring AOP aspect with annotations is not working for base class

I have annotation defined as below

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface OTPFlow {
}

And class A defined as below

public abstract class A {
  @OTPFlow
  public ModelAndView doSomething() {
    //do something and return ModelAndView
  }
}

Class B is a controller defined as below

@Controller
@RequestMapping(value = {"/someurl"})
public class B extends A {
  @RequestMapping(value = {"/get"}, method = {RequestMethod.POST, RequestMethod.GET})
  public ModelAndView get(HttpServletRequest request, HttpServletResponse response) {
    return doSomething();
  }
}

Aspect is defined as

@Component
@Aspect
public class OTPAspect {
private static final Logger logger = LoggerFactory.getLogger(OTPAspect.class);

@Pointcut("@annotation(OTPFlow)")
public void OTPFlow() {}

@Around("OTPFlow()")
public Object checkOTP(ProceedingJoinPoint joinPoint) {
    try {
        logger.info("Inside Aspect");
        return joinPoint.proceed();
    } catch (Throwable e) {
        throw new RuntimeException(e);
    }
}
}

The problem is when i access "/someurl/get" url, the aspect does not execute. But when i annotate "get" method of class B, aspect executes.

So basically, annotated methods of superclass does not invoke Aspect.

What is the issue? Is there any other way to achieve this? Any help would be appreciated. Thanks

What happens when spring applies the aspect, is that spring creates proxies that wrap your controller instance to intercept calls and add the aspect behaviour before calling the instance method. This has the effect, that any call to "this" from within your controller instance is directly invoked on that instance and will not be intercepted by the wrapping proxy. Therefore, the "get" method is called on the proxy class, which in turn will call the "get" method of the controller instance, and when the latter tries to call the "doSomething" method it will not pass through the proxied "doSomething", but through the internal one.

The way to handle this situation is to apply aspects directly to the methods of your class that will be externally called, in your case directly on the "get" method instead of the "doSomething"

I want to offer an alternative to what M. Deinum and Marios have said correctly: Use AspectJ instead of Spring AOP. AspectJ does not rely on proxies, is faster, more powerful and integrates nicely with Spring as described in Spring manual, Section 9.8, Using AspectJ with Spring applications . With AspectJ what you want to do works out of the box.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM