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
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 |