Working with Aspect-Oriented Programming
1. Enabling AspectJ Support (@EnableAspectJAutoProxy)
Example: Enable AspectJ auto-proxy
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AopConfig {}
Note: Enabled automatically by Spring Boot when
spring-boot-starter-aop is on classpath.
2. Creating Aspect Classes (@Aspect, @Component)
Example: Aspect bean with ordering
@Aspect
@Component
@Order(1)
public class LoggingAspect { /* advice methods */ }
3. Defining Pointcut Expressions (@Pointcut)
| Designator |
Matches |
execution(...) |
Method execution |
within(pkg..*) |
Within type |
this(Type) |
Proxy is instanceof |
target(Type) |
Target object is instanceof |
args(Type, ..) |
Arg types |
@annotation(X) |
Method annotated |
@within(X) / @target(X) |
Class annotated |
bean(name) |
Spring bean name |
Example: Service method pointcut expression
@Pointcut("execution(public * com.example.service..*(..))")
void anyServiceMethod() {}
4. Implementing Before Advice (@Before)
Example: Before advice: log method entry
@Before("anyServiceMethod()")
public void logEntry(JoinPoint jp) {
log.debug("ENTER {} args={}", jp.getSignature(), Arrays.toString(jp.getArgs()));
}
5. Implementing After Advice
| Annotation |
Fires |
@After |
Always (finally) |
@AfterReturning |
Only on normal return |
@AfterThrowing |
On exception |
Example: After-returning and after-throwing advice
@AfterReturning(pointcut="anyServiceMethod()", returning="result")
public void logReturn(JoinPoint jp, Object result) {
log.debug("RETURN {} = {}", jp.getSignature(), result);
}
@AfterThrowing(pointcut="anyServiceMethod()", throwing="ex")
public void logError(JoinPoint jp, Throwable ex) {
log.error("THROW {}: {}", jp.getSignature(), ex.toString());
}
6. Implementing Around Advice (@Around)
Example: Around advice: measure execution time
@Around("anyServiceMethod()")
public Object measure(ProceedingJoinPoint pjp) throws Throwable {
long start = System.nanoTime();
try { return pjp.proceed(); }
finally { log.info("{} took {}ms", pjp.getSignature(),
(System.nanoTime() - start)/1_000_000); }
}
Warning: Around advice MUST call pjp.proceed() or the target
method never executes.
7. Accessing Method Parameters (JoinPoint)
| API |
Returns |
getArgs() |
Method arguments |
getSignature() |
MethodSignature (name, params) |
getTarget() |
Underlying target bean |
getThis() |
Proxy |
getKind() |
method-execution, etc. |
8. Ordering Multiple Aspects (@Order)
| Annotation |
Effect |
@Order(1) |
Lower = outer (runs first on entry) |
Ordered interface |
Programmatic equivalent |
9. Implementing Cross-Cutting Concerns
| Concern |
Aspect Use |
| Logging |
Trace entry/exit |
| Security |
Pre/post auth checks |
| Transactions |
@Transactional |
| Caching |
@Cacheable |
| Retry |
@Retryable |
| Metrics |
Time + count invocations |
| Audit |
Capture actor + payload |
10. Using AspectJ Weaving
Spring AOP (Proxy)
- JDK or CGLIB proxies
- Public methods only
- No self-invocation
- Default in Spring
AspectJ (Weaving)
- Compile/load-time bytecode
- All methods (private, static, ctors)
- Self-invocation works
- Requires AspectJ compiler/agent
11. Using this() vs target() in Pointcuts
| Designator |
Matches Type Of |
this(X) |
The proxy |
target(X) |
The underlying target |
| JDK proxy implements interface |
Use interface in this(X) |
| CGLIB proxy is subclass |
Both this and target match class |