Implementing Aspect-Oriented Programming

1. Implementing Logging Aspects

Example: Method entry/exit logger

@Aspect @Component
public class LoggingAspect {
    @Around("@annotation(Loggable)")
    public Object log(ProceedingJoinPoint pjp) throws Throwable {
        var sig = pjp.getSignature().toShortString();
        log.debug("--> {} args={}", sig, Arrays.toString(pjp.getArgs()));
        long t0 = System.nanoTime();
        try {
            Object out = pjp.proceed();
            log.debug("<-- {} ({} ms)", sig, (System.nanoTime() - t0)/1_000_000);
            return out;
        } catch (Throwable ex) {
            log.warn("xx-- {} threw {}", sig, ex.toString());
            throw ex;
        }
    }
}

2. Implementing Performance Monitoring Aspects

Example: Micrometer timer

@Around("@annotation(io.micrometer.core.annotation.Timed)")
public Object timed(ProceedingJoinPoint pjp) throws Throwable {
    return Timer.builder("method.timer")
        .tag("method", pjp.getSignature().toShortString())
        .register(meterRegistry)
        .recordCallable(() -> {
            try { return pjp.proceed(); } catch (Throwable t) { throw new RuntimeException(t); }
        });
}

3. Implementing Security Aspects

UseDetail
@PreAuthorizeSpring Security AOP-based
Custom @RequiresScopeCheck JWT scope before invoke
Audit before/afterCapture actor, args (sanitized)

4. Implementing Transaction Aspects

DetailNote
Annotation@Transactional woven by Spring
Self-invocationBypasses proxy → no TX
PropagationREQUIRED, REQUIRES_NEW, NESTED
Rollback rulesRuntimeException by default

5. Implementing Caching Aspects

AnnotationEffect
@CacheableReturn cached if present
@CachePutAlways execute, update cache
@CacheEvictRemove on call
condition / unlessConditional caching

6. Implementing Audit Aspects

Example: @Auditable

@Around("@annotation(audit)")
public Object audit(ProceedingJoinPoint pjp, Auditable audit) throws Throwable {
    var actor = SecurityContextHolder.getContext().getAuthentication().getName();
    try {
        Object out = pjp.proceed();
        auditLog.write(actor, audit.action(), "SUCCESS", pjp.getArgs());
        return out;
    } catch (Throwable t) {
        auditLog.write(actor, audit.action(), "FAILURE", pjp.getArgs());
        throw t;
    }
}

7. Implementing Validation Aspects

MechanismDetail
@Validated on beanMethod-level Bean Validation
@Valid on paramsCascade into nested objects
Custom aspectDomain-specific pre-checks

8. Implementing Exception Handling Aspects

Example: @AfterThrowing

@AfterThrowing(pointcut = "execution(* com.acme.api..*(..))", throwing = "ex")
public void onError(JoinPoint jp, Throwable ex) {
    metrics.counter("errors", "method", jp.getSignature().toShortString()).increment();
}

9. Designing Pointcut Expressions

DesignatorExample
executionexecution(* com.acme.service..*(..))
withinwithin(com.acme.service..*)
@annotation@annotation(Loggable)
@withinClass-level annotation
beanbean(*Service)
argsargs(java.lang.String)

10. Implementing Around Advice

TypeDetail
@BeforeRun before; cannot prevent execution
@AfterAlways after (success or fail)
@AfterReturningOnly on success
@AfterThrowingOnly on exception
@AroundWrap; can short-circuit, modify args/return

11. Implementing Custom Annotations

Example: Marker annotation

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RateLimited {
    String key() default "";
    int permitsPerSecond() default 10;
}

12. Implementing Cross-Cutting Concerns

ConcernAOP Fit
Logging / metricsExcellent
Security checksExcellent
TransactionsExcellent
CachingGood
Business logicAvoid (hides intent)
Warning: Spring AOP uses proxies; calling another @Transactional/@Cacheable method on this bypasses the aspect.