spring-aop

Full Reference: See patterns.md for Performance Monitoring, Retry Logic, Audit Logging, Security Check, Rate Limiting, and Testing patterns.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "spring-aop" with this command: npx skills add claude-dev-suite/claude-dev-suite/claude-dev-suite-claude-dev-suite-spring-aop

Spring AOP

Full Reference: See patterns.md for Performance Monitoring, Retry Logic, Audit Logging, Security Check, Rate Limiting, and Testing patterns.

Quick Start

@SpringBootApplication @EnableAspectJAutoProxy public class Application {}

@Aspect @Component @Slf4j public class LoggingAspect {

@Around("execution(* com.example.service.*.*(..))")
public Object logExecution(ProceedingJoinPoint joinPoint) throws Throwable {
    String method = joinPoint.getSignature().toShortString();
    log.info("Executing: {}", method);

    long start = System.currentTimeMillis();
    Object result = joinPoint.proceed();
    long duration = System.currentTimeMillis() - start;

    log.info("Completed: {} in {} ms", method, duration);
    return result;
}

}

Pointcut Expressions

Method Execution

@Aspect @Component public class PointcutExamples {

// All methods in a package
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}

// Public methods
@Pointcut("execution(public * *(..))")
public void publicMethods() {}

// Methods starting with "get"
@Pointcut("execution(* get*(..))")
public void getters() {}

// Package and subpackages
@Pointcut("execution(* com.example..*.*(..))")
public void entireApplication() {}

}

Annotation-Based

@Aspect @Component public class AnnotationPointcuts {

// Methods annotated with @Transactional
@Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
public void transactionalMethods() {}

// Classes annotated with @Service
@Pointcut("@within(org.springframework.stereotype.Service)")
public void serviceBeans() {}

// With annotation binding
@Around("@annotation(loggable)")
public Object logWithAnnotation(ProceedingJoinPoint pjp, Loggable loggable) throws Throwable {
    String value = loggable.value();
    return pjp.proceed();
}

}

Combinations

@Aspect @Component public class CombinedPointcuts {

@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}

@Pointcut("execution(* com.example.repository.*.*(..))")
public void repositoryLayer() {}

// AND
@Pointcut("serviceLayer() && publicMethods()")
public void publicServiceMethods() {}

// OR
@Pointcut("serviceLayer() || repositoryLayer()")
public void dataLayer() {}

// NOT
@Pointcut("serviceLayer() && !execution(* get*(..))")
public void nonGetterServiceMethods() {}

}

Advice Types

@Around

@Aspect @Component public class AroundAdvice {

@Around("execution(* com.example.service.*.*(..))")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
    String methodName = joinPoint.getSignature().getName();
    Object[] args = joinPoint.getArgs();

    log.info("Before: {} with args: {}", methodName, Arrays.toString(args));

    try {
        Object result = joinPoint.proceed();
        log.info("After returning: {} returned: {}", methodName, result);
        return result;
    } catch (Exception e) {
        log.error("After throwing: {} threw: {}", methodName, e.getMessage());
        throw e;
    }
}

// Modify arguments
@Around("execution(* com.example.service.UserService.createUser(..))")
public Object sanitizeInput(ProceedingJoinPoint joinPoint) throws Throwable {
    Object[] args = joinPoint.getArgs();
    for (int i = 0; i < args.length; i++) {
        if (args[i] instanceof String str) {
            args[i] = sanitize(str);
        }
    }
    return joinPoint.proceed(args);
}

}

@Before, @After, @AfterReturning, @AfterThrowing

@Aspect @Component public class OtherAdvice {

@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
    log.info("Entering: {}", joinPoint.getSignature().toShortString());
}

@After("execution(* com.example.service.*.*(..))")
public void logAfter(JoinPoint joinPoint) {
    log.info("Completed: {}", joinPoint.getSignature().toShortString());
}

@AfterReturning(pointcut = "execution(* com.example.service.UserService.createUser(..))", returning = "user")
public void logCreatedUser(JoinPoint joinPoint, User user) {
    log.info("Created user: {}", user.getId());
}

@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "ex")
public void logException(JoinPoint joinPoint, Exception ex) {
    log.error("Exception in {}: {}", joinPoint.getSignature().toShortString(), ex.getMessage());
}

}

Custom Annotations

@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Loggable { String value() default ""; boolean logArgs() default true; boolean logResult() default true; LogLevel level() default LogLevel.INFO; }

@Aspect @Component @Slf4j public class LoggableAspect {

@Around("@annotation(loggable)")
public Object logMethod(ProceedingJoinPoint joinPoint, Loggable loggable) throws Throwable {
    String methodName = joinPoint.getSignature().toShortString();
    String message = loggable.value().isEmpty() ? methodName : loggable.value();

    if (loggable.logArgs()) {
        log.info("Entering {} with args: {}", message, Arrays.toString(joinPoint.getArgs()));
    }

    long start = System.currentTimeMillis();
    Object result = joinPoint.proceed();

    if (loggable.logResult()) {
        log.info("Exiting {} with result: {} ({}ms)", message, result, System.currentTimeMillis() - start);
    }
    return result;
}

}

// Usage @Service public class UserService { @Loggable(value = "Creating user", logResult = false) public User createUser(CreateUserRequest request) { return userRepository.save(new User(request)); } }

Aspect Ordering

@Aspect @Component @Order(1) // Executes first public class SecurityAspect { }

@Aspect @Component @Order(2) // Executes second public class LoggingAspect { }

@Aspect @Component @Order(3) // Executes third public class PerformanceAspect { }

Best Practices

  • Use specific pointcuts (not too broad)

  • Order aspects with @Order

  • Use custom annotations for clarity

  • Avoid complex logic in aspects

  • Monitor performance impact

  • Test aspects in isolation

  • Don't catch exceptions silently

  • Don't modify shared state

  • Don't use for core business logic

Common Pitfalls

Error Cause Solution

Aspect not applied Bean not Spring-managed Use @Component or @Bean

Self-invocation Internal call bypasses proxy Use self-injection

Wrong order Aspects not ordered Use @Order

Performance Aspect too broad Narrow pointcut

Quick Troubleshooting

Issue Possible Cause Solution

Aspect not executing Bean not Spring-managed Ensure class has @Component

Self-invocation doesn't trigger Internal call bypasses proxy Use self-injection

Wrong execution order Missing @Order Add @Order with priority

Performance degradation Pointcut too broad Narrow scope, use custom annotations

Reference Documentation

  • Spring AOP

  • AspectJ Pointcut Expressions

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Security

rust-security

No summary provided by upstream source.

Repository SourceNeeds Review
Security

dotnet-security

No summary provided by upstream source.

Repository SourceNeeds Review
Security

spring-security

No summary provided by upstream source.

Repository SourceNeeds Review