In the previous lecture we covered the basic concepts of AOP. But there's a big difference between "knowing the terms" and actually getting how it works. Let's peek under the hood and dig into the details.
1. Aspect: more than just a module
We already know an aspect is a module for cross-cutting concerns. But how does Spring create and manage it?
Aspect lifecycle
An aspect in Spring is not just a class annotated with @Aspect. It's a first-class citizen of the Spring container with its own lifecycle:
- Initialization: Spring creates aspects at a very early stage of context loading
- Proxying: proxies for target beans are created based on aspects
- Injection: an aspect can use other beans via
@Autowired - Execution: Spring calls aspect methods when triggers fire
How aspects behave
Unlike regular beans, aspects have a few important quirks:
- Prioritization: when multiple aspects target the same method, the order of execution matters:
@Aspect @Order(1) // First check permissions public class SecurityAspect { ... } @Aspect @Order(2) // Then log public class LoggingAspect { ... } - Self-application: by default aspects are not applied to methods inside the aspects themselves — this protects you from recursion
2. Pointcut: fine-tuning where advice is applied
In the previous lecture we saw the basic pointcut syntax. Now let's break down how Spring processes them and what advanced options exist.
Anatomy of a pointcut
A pointcut is not just a string with wildcards. It's a powerful language for describing where advice should be applied:
@Pointcut("execution(* com.example.service.*.*(..)) && @annotation(Secured)")
public void securedMethods() {}
Here's what's happening:
execution()— defines a pattern to match methods.&&— combines conditions.@annotation()— checks for the presence of an annotation.
Composing pointcuts
You can combine pointcuts to build more complex logic:
@Pointcut("inService() && secured()")
public void securedServiceMethods() {}
@Pointcut("within(com.example.service.*)")
public void inService() {}
@Pointcut("@annotation(Secured)")
public void secured() {}
Common patterns used:
execution(* com.example..*(..)): All methods under thecom.examplepackage.within(com.example.service.*): Methods in specific classes.@annotation(org.springframework.transaction.annotation.Transactional): Methods annotated with a specific annotation.
How pointcuts work under the hood
Spring "listens" to pointcut definitions and binds them to join points (for example, methods) that match the pattern. Those join points become the places where aspects will run.
3. Advice: execution mechanics
We know about advice types (@Before, @After, etc.), but how does Spring execute them?
Order of advice execution
When a method has multiple advices applied, they execute in the following order:
@Around (start)
@Before
→ Method
@AfterReturning/@AfterThrowing
@After
@Around (end)
Access to context
Advices have access to rich context information:
@Before("execution(* *(..))")
public void beforeMethod(JoinPoint jp) {
String methodName = jp.getSignature().getName();
Object[] args = jp.getArgs();
Object target = jp.getTarget();
}
Example: Before
@Before("execution(* com.example.service.OrderService.placeOrder(..))")
public void logBeforePlaceOrder() {
System.out.println("Before calling method placeOrder()");
}
Example: After
@After("execution(* com.example.service.OrderService.placeOrder(..))")
public void logAfterPlaceOrder() {
System.out.println("After method placeOrder()");
}
Example: Around
@Around("execution(* com.example.service.OrderService.placeOrder(..))")
public Object logAroundPlaceOrder(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Before calling method: " + joinPoint.getSignature().getName());
Object result = joinPoint.proceed(); // Invoke the method
System.out.println("After method call");
return result;
}
Why does this work?
AOP in Spring is based on using proxy objects. When you call a method, Spring replaces your implementation with a proxy that checks all aspects associated with that method. If the method matches a pointcut, Spring runs the advice linked to it.
Helpful notes:
- Cross-cutting concerns are a great fit for AOP. Typical examples:
- Logging.
- Transaction management.
- Security checks.
- Measuring execution time.
- Don't overuse AOP! Your aspects should be lightweight and easy to understand.
- If the logic becomes complex, aspects might not be the best solution.
Table: AOP terms summary
| Term | Description | Example |
|---|---|---|
| Aspect | A module that contains behavior for cross-cutting concerns | Logging method calls |
| Pointcut | Defines where an aspect should be applied | execution(* com.example.service.*.*(..)) |
| Advice | A concrete action executed at selected join points | Logging before a method call (@Before) |
Now you understand how aspects (modules) apply their actions (advice) at specific points (pointcuts). We've covered the basic AOP concepts. In the next lecture we'll see how to apply this knowledge in practice to solve real problems — logging, security, and transaction management. For now it's important to understand that AOP is not just Spring magic, but a well-thought-out mechanism with clear execution rules.
GO TO FULL VERSION