Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Spring AOP proxies: self-invocation bypasses proxy advice

Last updated: 29 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

A Spring proxy can intercept calls entering through the proxy reference, but an ordinary call from a target object to itself does not re-enter that proxy.

Download Spring source kit

This lesson uses the downloadable source kit: Java 21, Spring Boot 4.0.8 and its managed Spring Framework 7 dependencies. The version is pinned for repeatable builds.

The reference used for the call matters

The CounterTarget outer() method calls inner(). The ProxyFactory fixture counts one advised call when the caller invokes outer through the proxy. If both methods were expected to open separate transactional boundaries, that expectation would be wrong for this call path.

The test uses an advice counter rather than a fake database flag. It isolates proxy dispatch. Transaction rollback needs a database test as well; a method interception count alone cannot prove a transaction manager committed or rolled back anything.

Move a boundary when it belongs elsewhere

Separate orchestration and the transactional collaborator when that reflects application ownership. Calling the collaborator through its injected proxy then makes the entry boundary inspectable. Do not scatter container lookups or self-injected fields simply to make annotation interception appear to work.

The same call-path issue matters for caching and async annotations. A final method also cannot be overridden by a class-based proxy. Choose the proxy model and inspect the actual bean supplied to callers rather than assuming every annotated Java method is intercepted.

Checked source

Java
AtomicInteger advised = new AtomicInteger();
ProxyFactory factory = new ProxyFactory(new CounterTarget());
factory.addAdvice((MethodInterceptor) invocation -> {
    advised.incrementAndGet(); return invocation.proceed();
});
Counter proxy = (Counter) factory.getProxy();
proxy.outer();
System.out.println(advised.get());

Test the boundary

Run mvn test in the source-kit directory. CoreBoundaryTest checks the behavior described here. Java excerpts belong to the named source-kit classes; they are not independent source files unless the complete class is shown.

Costs and boundaries

Advice adds dispatch and the work inside the interceptor. The one-call fixture demonstrates a boundary, not a universal proxy overhead benchmark.

Common Mistakes

  • Self-invocation is still an ordinary target call.
  • An annotation is not proof that the caller used a proxy.
  • Do not infer database behavior from interception alone.

Read next

Transaction proxies, Cache keys, Java reflection: inspect types without breaking contracts.

spring
spring-boot
proxy-self-invocation
Storage details