Why Spring AOP Doesn’t Apply to ‘this’ Calls and How to Fix It
This article explains why Spring AOP proxies are not applied when a bean invokes its own methods via the this reference, compares JDK and CGLIB proxy mechanisms, and shows how to enable proxy exposure or use AopContext to achieve the desired AOP behavior.
Problem Overview
Spring AOP weaves aspect code into bean methods at runtime using proxies. When a bean calls its own method via this, the call bypasses the proxy, so the advice is not executed.
Example Scenario
A CouponService class provides a deposit() method. An @Around advice is defined to record the execution time of pay(). The controller invokes deposit() through the injected bean, but the internal call uses this.deposit(), which refers to the plain target object, so the advice never runs.
Why this Bypasses the Proxy
The this reference points to the original CouponService instance created by the developer, not the Spring‑generated proxy.
The bean injected into other components is a proxy; only calls made on that proxy trigger the aspect logic.
Proxy Creation Mechanisms
JDK dynamic proxy : works only for beans that implement an interface.
CGLIB proxy : creates a subclass of the concrete class and overrides its methods, allowing proxying of classes without interfaces.
Enabling AOP (Non‑Spring‑Boot Applications)
Add the AOP starter dependencies and annotate a configuration class with @EnableAspectJAutoProxy. This registers AspectJAutoProxyRegistrar via the ImportBeanDefinitionRegistrar interface, which prepares the necessary infrastructure beans.
Bean Post‑Processing and Proxy Wrapping
During bean initialization, AnnotationAwareAspectJAutoProxyCreator (a BeanPostProcessor) runs after the original bean is instantiated. Its postProcessAfterInitialization method invokes wrapIfNecessary. If the bean matches any AOP pointcut, a proxy (JDK or CGLIB) is created and returned as the bean instance.
Solutions for Self‑Invocation
To make internal method calls go through the proxy, use one of the following approaches:
Inject the bean into itself so that the injected reference is the proxy, e.g.
@Autowired
private CouponService self;
public void someMethod(){
self.deposit(); // goes through proxy
}Obtain the current proxy from AopContext. This requires exposing the proxy:
@EnableAspectJAutoProxy(exposeProxy = true)Then invoke the method via the proxy:
AopContext.currentProxy().deposit();Practical Configuration
When using AopContext, ensure the @EnableAspectJAutoProxy annotation includes exposeProxy = true. After applying either self‑injection or proxy exposure, the deposit() call is routed through the Spring proxy and the @Around advice correctly records execution time.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
JavaEdge
First‑line development experience at multiple leading tech firms; now a software architect at a Shanghai state‑owned enterprise and founder of Programming Yanxuan. Nearly 300k followers online; expertise in distributed system design, AIGC application development, and quantitative finance investing.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
