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