Spring AOP decouples cross-cutting concerns such as logging, execution-time metrics, authorization checks, and exception handling from business code. It reduces duplicated code, lowers invasiveness, and improves maintainability. Core keywords: Spring AOP, dynamic proxy, pointcut expressions.
Technical specification snapshot
| Parameter | Description |
|---|---|
| Language | Java |
| Framework | Spring Boot / Spring AOP |
| License | CC 4.0 BY-SA (original content declaration) |
| Star Count | Not provided in the original article |
| Core Dependencies | spring-boot-starter-aop, AspectJ, CGLIB |
Spring AOP extracts cross-cutting logic from business methods
AOP stands for Aspect-Oriented Programming. At its core, it applies unified handling to an entire class of problems. It does not replace business logic directly. Instead, it centralizes repetitive concerns such as logging, authorization, transactions, and monitoring.
In the Spring ecosystem, IoC manages objects, while AOP applies cross-cutting enhancement. When combined, business code retains only the core workflow, and non-business logic is delegated to aspects. The result is cleaner code.
AI Visual Insight: The image presents a system view with multiple business modules side by side, highlighting that requirements such as performance analysis and logging span multiple controller or service-layer methods, making them ideal candidates for a unified AOP entry point.
Manual instrumentation quickly causes duplicated code to grow
If you need to measure the execution time of every API or method, the most direct approach is to record timestamps before and after each method call. However, as the project grows and modules increase, manual instrumentation significantly raises both development and maintenance costs.
AI Visual Insight: The image illustrates a flow where time-recording logic is inserted before and after the target method, reflecting the typical AOP wrapping model of “before enhancement + original method execution + after enhancement.”
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
This configuration introduces the capabilities required by Spring AOP and serves as the foundational dependency for aspect development.
The smallest useful Spring AOP practice usually starts with around advice
Around advice is the best fit for execution-time measurement because it can wrap both the pre- and post-execution logic of a target method while also controlling whether the original method should proceed.
@Slf4j
@Aspect
@Component
public class TimeAspect {
@Around("execution(* com.example.demo..*.*(..))")
public Object timeRecord(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis(); // Record start time
Object result = pjp.proceed(); // Execute the target method
long end = System.currentTimeMillis(); // Record end time
log.info("{} 耗时 {} ms", pjp.getSignature(), (end - start)); // Output execution time
return result; // Return the original result
}
}
This code implements unified execution-time measurement for all methods in the specified package without modifying the original business code.
AI Visual Insight: The image shows log output produced after aspect execution, demonstrating that multiple API methods are proxied uniformly and their execution times are printed, which confirms that the pointcut expression successfully matched the target methods.
Four core Spring AOP objects determine how deeply you understand it
A Pointcut is a rule that defines which methods require enhancement. A Join Point is a concrete method that gets matched. Advice is the enhancement logic itself. An Aspect is the combination of pointcuts and advice.
Among these four concepts, Pointcut and Join Point are the easiest to confuse. The former is the matching rule; the latter is the actual set of methods that the rule matches.
AI Visual Insight: The image focuses on the structure of an execution expression, which typically includes the return type, package path, class name, method name, and parameter pattern, showing how precise matching works based on method signatures.
AI Visual Insight: The image illustrates the enhancement relationship between advice and the target method, emphasizing that advice is not the business implementation itself, but shared logic added around a method invocation.
AI Visual Insight: The image conveys the composition relationship of “Aspect = Pointcut + Advice,” showing that an aspect class is fundamentally an organizational unit for rules and enhancement behavior.
Spring AOP provides five advice types to cover both normal and exceptional flows
Common advice types include @Before, @After, @AfterReturning, @AfterThrowing, and @Around. Among them, @Around is the most powerful because it can explicitly decide whether to execute the target method.
@Slf4j
@Aspect
@Component
public class AspectDemo {
@Before("execution(* com.example.demo.controller.*.*(..))")
public void doBefore() {
log.info("执行 Before 方法"); // Before advice
}
@AfterReturning("execution(* com.example.demo.controller.*.*(..))")
public void doAfterReturning() {
log.info("执行 AfterReturning 方法"); // Execute after a normal return
}
@AfterThrowing("execution(* com.example.demo.controller.*.*(..))")
public void doAfterThrowing() {
log.info("执行 AfterThrowing 方法"); // Execute when an exception occurs
}
}
This code demonstrates how different advice types are triggered differently for normal returns versus exceptional exits.
Using @Pointcut eliminates repeated expressions
When multiple pieces of advice share the same matching rule, you should extract the pointcut expression into a common method to improve readability and maintainability.
@Pointcut("execution(* com.example.demo.controller.*.*(..))")
private void pt() {}
@Before("pt()")
public void before() {
log.info("before..."); // Reuse the shared pointcut
}
This code uses @Pointcut to manage the pointcut centrally and avoids rewriting long expressions in multiple advice methods.
When multiple aspects coexist, you must explicitly control execution order
If multiple aspects match the same method at the same time, the default order is not ideal for long-term maintenance. You should use @Order to define priority explicitly. The smaller the number, the earlier the before advice runs.
For @Before advice, higher-priority aspects execute first. For @After advice, higher-priority aspects execute later. This is the typical wrapping behavior of a call stack.
AI Visual Insight: The image shows the execution log order when multiple aspect classes match the same target method, making it easy to see that before advice follows forward order while after advice follows reverse order.
AI Visual Insight: The image highlights that the @Order annotation controls aspect priority, typically using numeric values to define the wrapping order of before and after advice in the proxy chain.
Annotation-based pointcuts are better for irregular method sets
If multiple target methods are distributed across different classes and their names do not follow a consistent pattern, execution expressions become cumbersome. In that case, you should use @annotation instead.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAspect {
}
This code defines a runtime-visible method-level annotation used to declare which methods should receive aspect enhancement.
@Before("@annotation(com.example.demo.aspect.MyAspect)")
public void before() {
log.info("MyAspect -> before..."); // Intercept only annotated methods
}
This code implements precise interception by annotation and is especially suitable for scenarios such as authorization checks, audit logging, and idempotency control.
The underlying essence of Spring AOP is dynamic proxy
Spring AOP does not modify the original class directly. Instead, it creates a proxy object for the target object. Calls go through the proxy, which allows the enhancement logic to be woven in.
If the target class implements an interface, Spring usually prefers JDK dynamic proxy. If the target class does not implement an interface, Spring usually uses CGLIB to generate a subclass-based proxy.
AI Visual Insight: The image shows the call chain among the client, proxy object, and target object, illustrating that the proxy layer is responsible for request interception, enhancement weaving, and delegated invocation.
AI Visual Insight: The image breaks down the three roles in the proxy pattern—Subject, RealSubject, and Proxy—helping explain why Spring AOP emphasizes interface-based proxying and separation of responsibilities.
JDK dynamic proxy fits interface-driven business models
public class JDKInvocationHandler implements InvocationHandler {
private final Object target;
public JDKInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是中介, 开始代理"); // Before enhancement
Object retVal = method.invoke(target, args); // Invoke the target method
System.out.println("我是中介, 代理结束"); // After enhancement
return retVal;
}
}
This code shows how a JDK proxy wraps interface method invocations through InvocationHandler.
CGLIB dynamic proxy fits classes without interfaces
public class CglibInterceptor implements MethodInterceptor {
private final Object target;
public CglibInterceptor(Object target) {
this.target = target;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("我是中介, 开始代理"); // Before enhancement
Object result = proxy.invoke(target, args); // Invoke the target method
System.out.println("我是中介, 代理结束"); // After enhancement
return result;
}
}
This code shows that CGLIB enhances methods through subclass-based proxies and does not rely on business interfaces.
In production, AOP should be used first for stable cross-cutting scenarios
The most common real-world scenarios include API execution-time measurement, operation logging, unified authorization, idempotency control, exception instrumentation, and transaction boundary management. AOP is best suited to shared logic that is reusable and loosely coupled to business behavior.
However, you should not overuse AOP in core business branches. Otherwise, the call chain becomes less visible and troubleshooting becomes harder. The best strategy is simple: keep cross-cutting concerns in aspects, and keep the main business flow in the service layer.
FAQ
What is the difference between Spring AOP and an interceptor?
An interceptor mainly operates on the web request pipeline and intercepts by URL or request lifecycle. Spring AOP works at the method level and can enhance behavior precisely by package, class, method, parameters, or annotation, so its granularity is finer.
Why is around advice the most commonly used?
Because it can weave logic both before and after the target method, control whether the original method executes through proceed(), and also take over return values and exception handling. It provides the most complete capability set.
How should you choose between JDK dynamic proxy and CGLIB?
Prefer JDK dynamic proxy when interfaces are available because the structure is clearer. Use CGLIB when no interface exists. For Spring developers, the framework usually chooses automatically, but understanding the principles and limitations of both approaches is what matters.
Core summary: This article systematically reconstructs the core knowledge of Spring AOP, from pointcuts, join points, advice, and aspects to practical usage of @Pointcut, @Order, and @annotation, and then to the underlying principles of JDK and CGLIB dynamic proxies. It helps developers quickly master cross-cutting capabilities such as logging, execution-time measurement, and authorization checks.