스프링 부트 AOP 사용 예시

TMT

스프링 부트에서 AOP(Aspect-Oriented Programming)를 잘 활용한 예시는 다양한 관심사 분리 및 횡단 관심사를 효과적으로 관리하는 데 있습니다. 로깅 외에도 AOP는 여러 상황에서 코드의 중복을 줄이고, 모듈화된 코드를 작성하는 데 큰 도움을 줄 수 있습니다. 다음은 AOP를 잘 사용한 예시들입니다:

1. 메서드 실행 시간 측정:

  • 설명: 메서드의 실행 시간을 측정해 성능을 모니터링하고 병목 지점을 파악할 수 있습니다.
  • 예시: @Around 어노테이션을 사용해 메서드 실행 전후의 시간을 기록하여 실행 시간을 계산하고 로그로 출력하거나 성능 모니터링 도구로 보냅니다.
@Aspect
@Component
public class PerformanceLoggingAspect {

    @Around("@annotation(com.example.annotation.TrackExecutionTime)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object proceed = joinPoint.proceed();
        long executionTime = System.currentTimeMillis() - start;
        System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms");
        return proceed;
    }
}

2. 보안 검증 및 권한 체크:

  • 설명: 특정 메서드가 실행되기 전에 사용자 권한을 확인하고, 권한이 부족할 경우 실행을 차단할 수 있습니다.
  • 예시: @Before 어노테이션을 사용해 메서드 호출 전에 현재 사용자의 권한을 체크하고, 권한이 부족할 경우 예외를 던집니다.
@Aspect
@Component
public class SecurityAspect {

    @Before("@annotation(com.example.annotation.RequiresAdmin)")
    public void checkAdminAccess(JoinPoint joinPoint) {
        if (!CurrentUser.hasRole("ADMIN")) {
            throw new AccessDeniedException("User does not have ADMIN privileges");
        }
    }
}

3. 트랜잭션 관리:

  • 설명: 특정 메서드나 계층에 대해 트랜잭션의 시작과 종료를 일괄적으로 처리할 수 있습니다. 스프링의 @Transactional이 기본적이지만, AOP를 통해 더 복잡한 트랜잭션 로직을 구현할 수도 있습니다.
  • 예시: 커스텀 트랜잭션 롤백 로직이나 조건부 트랜잭션 관리를 위한 AOP 사용.

4. 캐싱 로직 적용:

  • 설명: 메서드 호출 시 특정 조건을 만족하면 캐시된 값을 반환하고, 그렇지 않으면 실제 메서드를 실행하여 값을 캐싱할 수 있습니다.
  • 예시: @Around 어노테이션을 사용해 메서드가 호출될 때 캐시를 확인하고, 캐시가 없으면 메서드를 실행하고 결과를 캐시에 저장합니다.

5. 데이터 검증 및 전처리:

  • 설명: 메서드 실행 전에 인수 검증이나 데이터 전처리를 일괄적으로 적용할 수 있습니다.
  • 예시: @Before 어노테이션을 사용해 메서드 인수를 검증하고, 특정 조건에 맞지 않으면 예외를 발생시킵니다.
@Aspect
@Component
public class ValidationAspect {

    @Before("@annotation(com.example.annotation.ValidateInput)")
    public void validateInputs(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            if (arg instanceof String && ((String) arg).isEmpty()) {
                throw new IllegalArgumentException("String arguments must not be empty");
            }
        }
    }
}

6. 모니터링 및 메트릭 수집:

  • 설명: 메서드 호출 시 성능이나 사용 빈도 등을 수집하여 모니터링 도구와 연계할 수 있습니다.
  • 예시: AOP를 사용해 메서드 호출 시 메트릭을 수집하고, Prometheus나 ELK 스택으로 보냅니다.

7. 트레이싱 및 디버깅:

  • 설명: 메서드 호출 시 파라미터와 반환값을 로깅하여 디버깅 시 유용한 정보를 제공합니다.
  • 예시: @Around를 사용해 메서드 호출 전에 인수를 로깅하고, 실행 후 반환값을 기록합니다.
@Aspect
@Component
public class TracingAspect {

    @Around("execution(* com.example.service.*.*(..))")
    public Object traceMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Method called: " + joinPoint.getSignature());
        System.out.println("With arguments: " + Arrays.toString(joinPoint.getArgs()));
        Object result = joinPoint.proceed();
        System.out.println("Method returned: " + result);
        return result;
    }
}

8. 다중 언어 지원 (국제화):

  • 설명: 메서드 호출 시 AOP를 통해 국제화(i18n) 컨텍스트를 설정할 수 있습니다. 예를 들어, 요청의 헤더나 세션에서 언어 정보를 추출하여 로케일을 설정할 수 있습니다.

결론:

AOP는 로깅 외에도 다양한 관심사를 코드에서 분리하여 중복을 줄이고, 코드의 가독성과 유지보수성을 높이는 데 유용합니다. 보안, 성능 모니터링, 데이터 검증, 트랜잭션 관리, 캐싱 등 다양한 상황에서 AOP를 잘 활용하면 코드를 간결하고 체계적으로 유지할 수 있습니다.

Edit this page

Search the archive

Find a page by title, or search the text inside one.