Spring AOP 핵심 정리
Spring AOP란
Spring AOP는 공통 관심사를 비즈니스 로직과 분리해서 다루기 위한 도구다. 로깅, 트랜잭션, 보안, 성능 측정처럼 여러 계층에 반복되는 코드를 핵심 로직 밖으로 꺼내고 싶을 때 주로 사용한다.
핵심은 “원래 객체를 직접 호출하는 것처럼 보이지만, 실제로는 프록시가 앞단에서 끼어들어 부가 작업을 수행한다”는 점이다.
왜 필요한가
서비스 메서드마다 다음 코드가 반복된다고 생각해보자.
- 호출 시작 로그
- 실행 시간 측정
- 권한 확인
- 트랜잭션 시작과 종료
이런 코드는 본질적으로 주문 생성, 결제 승인, 회원 조회 같은 업무 로직과는 별개다. AOP를 쓰면 이 반복을 한곳으로 모을 수 있다.
Spring AOP의 구성 요소
Aspect: 공통 관심사를 담는 클래스Advice: 언제 동작할지 정의하는 실제 부가 로직Pointcut: 어떤 대상에 적용할지 지정하는 조건Join Point: Advice가 끼어들 수 있는 지점Proxy: 실제 객체 대신 호출을 가로채는 래퍼 객체
자주 쓰는 Advice
@Before: 메서드 실행 전@AfterReturning: 정상 반환 후@AfterThrowing: 예외 발생 후@After: 성공/실패와 무관하게 종료 후@Around: 전후를 모두 감싸며 가장 강력함
실무에서는 @Around를 남용하기보다 목적이 명확할 때만 쓰는 편이 좋다. 로그, 시간 측정 정도는 좋지만 비즈니스 분기를 넣기 시작하면 로직이 흐려진다.
프록시 기반이라는 점이 중요하다
Spring AOP는 기본적으로 프록시 기반으로 동작한다. 그래서 다음 제약을 반드시 기억해야 한다.
- 같은 빈 내부의 self-invocation에는 AOP가 적용되지 않는다.
private메서드에는 적용되지 않는다.- final 클래스나 final 메서드는 프록시 방식에 따라 제한이 생길 수 있다.
예를 들어 같은 서비스 안에서 this.save()를 호출하면 프록시를 거치지 않기 때문에 @Transactional, @Async, 커스텀 AOP가 기대대로 동작하지 않을 수 있다.
언제 쓰는 게 좋은가
- 요청/응답 로깅
- 메서드 실행 시간 측정
- 인증/인가 체크
- 공통 예외 로깅
- 멱등성 키 검증 같은 횡단 관심사
반대로 아래는 AOP보다 다른 설계가 낫다.
- 도메인 규칙 분기
- 서비스 간 협력 순서 제어
- 복잡한 상태 전이
이런 것은 AOP로 숨기기보다 서비스/도메인 객체 안에서 명시적으로 드러내는 편이 유지보수에 낫다.
예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Aspect
@Component
public class LoggingAspect {
@Around("execution(* com.example..service..*(..))")
public Object logExecution(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
try {
return joinPoint.proceed();
} finally {
long elapsed = System.currentTimeMillis() - start;
System.out.println(joinPoint.getSignature() + " took " + elapsed + "ms");
}
}
}
정리
Spring AOP는 “중복되는 부가 작업을 핵심 로직에서 분리하는 도구”로 이해하면 된다. 다만 프록시 기반이라는 구현 제약을 모르고 쓰면 왜 동작 안 하지?가 자주 발생한다. AOP는 강력하지만, 비즈니스 자체를 숨기는 도구로 쓰기 시작하면 오히려 가독성과 추적성이 떨어진다.
댓글
아직 댓글이 없습니다