spring-projects/spring-framework
AOP (Aspect-Oriented Programming)
Active contributors: Juergen Hoeller, Sam Brannen
Spring's AOP capabilities turn declarative annotations like @Transactional, @Async, @Cacheable, @PreAuthorize, and @Validated into runtime behavior. This page explains how the framework's AOP machinery works and how the major annotation-driven features plug into it.
Two implementations: proxies vs weaving
Spring offers two different AOP implementations:
| Feature | spring-aop (proxy) |
spring-aspects (AspectJ weaving) |
|---|---|---|
| Mechanism | Runtime proxy generation (JDK or CGLIB) | Compile-time or load-time bytecode rewriting |
| Setup | None — automatic when annotations are used | AspectJ compiler or -javaagent:spring-instrument.jar |
| Self-invocation | ❌ Bypassed | ✅ Works |
| Final classes/methods | ❌ Cannot proxy | ✅ Works |
| Performance overhead | One additional method call per intercepted method | Inlined into the method |
| GraalVM native image | First-class | Trickier |
The proxy approach is the default and is what most apps use. AspectJ weaving is opt-in for cases where proxies don't fit.
Proxy AOP: how it works
graph LR
BPP["BeanPostProcessor: AnnotationAwareAspectJAutoProxyCreator"]
BEAN[Original bean] -->|"postProcessAfterInitialization"| BPP
BPP -->|"determine matching advisors"| ADVISORS[Advisor list]
BPP -->|"if advisors > 0"| FACTORY[ProxyFactory.getProxy]
FACTORY -->|"target has interfaces"| JDK[JDK Dynamic Proxy]
FACTORY -->|"target is a class"| CG[CGLIB Subclass]
JDK --> RESULT[Proxied bean replaces original]
CG --> RESULTEvery annotation that triggers AOP (@EnableTransactionManagement, @EnableAsync, @EnableCaching, @EnableAspectJAutoProxy) imports the same BeanPostProcessor, AnnotationAwareAspectJAutoProxyCreator, plus the appropriate Advisor beans for the feature.
When BeanPostProcessors run during the bean lifecycle, the auto-proxy creator checks if any registered Advisor matches the bean's class/methods. If so, it returns a proxy in place of the bean. Other beans that depend on this one will receive the proxy.
Method invocation through the proxy
sequenceDiagram
participant Caller
participant Proxy
participant Chain as AdvisorChain (MethodInterceptor list)
participant Target as target bean
Caller->>Proxy: instance.method(args)
Proxy->>Proxy: build chain for this method (cached)
Proxy->>Chain: chain.proceed
Chain->>Chain: ExposeInvocationInterceptor (sets ThreadLocal)
Chain->>Chain: TransactionInterceptor (begins tx)
Chain->>Chain: CacheInterceptor (checks cache)
Chain->>Chain: ... other matched advice ...
Chain->>Target: target.method(args)
Target-->>Chain: result
Chain-->>Proxy: result
Proxy-->>Caller: resultThe chain is per method, not per call — ProxyMethodInvocation caches the resolved interceptor list for each method.
Annotation-driven features
@Transactional
- Defined in spring-tx
- Implemented as
TransactionInterceptor(aMethodInterceptor) - Pointcut:
TransactionAttributeSourcePointcutmatches methods/classes carrying@Transactional - Around-advice: begins a transaction, calls
proceed(), commits or rolls back based on the outcome
@Async
- Defined in spring-context
- Implemented as
AsyncExecutionInterceptor - Submits the actual invocation to a
TaskExecutorand returns aFuture(or void) - Importer:
@EnableAsync
@Cacheable / @CachePut / @CacheEvict
- Defined in
spring-context(cache abstraction) - Implemented as
CacheInterceptor - Around-advice: looks up cache, returns cached value or invokes target then stores
- Importer:
@EnableCaching
@PreAuthorize / @PostAuthorize
- Defined in Spring Security (a separate project)
- Built on the same
AnnotationAwareAspectJAutoProxyCreatorinfrastructure here
@Validated (method validation)
- Defined in
spring-context(org.springframework.validation.beanvalidation.MethodValidationInterceptor) - Validates
@Validparameters and return values using JSR-303 / Bean Validation
Custom advice
To add your own around-advice:
Implement
org.aopalliance.intercept.MethodInterceptor(or use@Aspectstyle):public class TimingInterceptor implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { long start = System.nanoTime(); try { return invocation.proceed(); } finally { long elapsed = System.nanoTime() - start; // record metric } } }Pair with a pointcut to form an
Advisor:@Bean public Advisor timingAdvisor() { AspectJExpressionPointcut p = new AspectJExpressionPointcut(); p.setExpression("execution(* com.example..*Service.*(..))"); return new DefaultPointcutAdvisor(p, new TimingInterceptor()); }Annotate a
@Configurationwith@EnableAspectJAutoProxyto install the auto-proxy creator (Spring Boot does this automatically when AOP is on the classpath).
@Aspect style
Alternatively, write a class annotated @Aspect with @Pointcut and @Around (or @Before, etc.) methods:
@Aspect
@Component
public class TimingAspect {
@Around("execution(* com.example..*Service.*(..))")
public Object time(ProceedingJoinPoint pjp) throws Throwable { ... }
}AspectJAdvisorFactory extracts advisors from @Aspect beans at startup.
Limitations of proxy-based AOP
These bite reliably enough that the framework's documentation calls them out repeatedly:
- Self-invocation is not advised. Calling another
@Transactionalmethod onthisfrom within the same bean does not go through the proxy. The recommendation is to inject the proxy of yourself (Spring 4.3+ supports self-injection by type) or restructure so the call crosses bean boundaries. finalclasses cannot be CGLIB-proxied;finalmethods cannot be advised. Make the class non-final or extract the method into an interface.privateandpackage-privatemethods are not advised by proxies.- Constructors can't be advised.
- Calls from within the framework's own infrastructure (e.g.,
BeanPostProcessorcallbacks during initialization) may not see proxies that are themselves still being initialized.
If any of these are a problem, switch to AspectJ via spring-aspects.
AOT and AOP
For native-image builds, proxies must be registered as runtime hints. The framework's auto-proxy creator implements BeanRegistrationAotContributor to ensure each proxy class is reachable in the native image. Custom Advisor beans are picked up automatically.
See also
- spring-aop — proxy implementation
- spring-aspects — AspectJ alternative
- spring-tx —
@Transactionalis the most common AOP user - spring-instrument — load-time weaving agent
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.