스프링 부트 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를 잘 활용하면 코드를 간결하고 체계적으로 유지할 수 있습니다.