Files

5.3 KiB

AOP 사용 기준

목적

AOP는 비즈니스 로직을 숨기는 우회 수단이 아니라,
여러 타입과 객체를 가로지르는 cross-cutting concern 을 모듈화할 때만 사용한다.

공식 의미

  • Spring AOP는 OOP를 보완하는 방식이다.
  • AOP의 핵심 단위는 class가 아니라 aspect다.
  • Spring AOP는 proxy-based다.
  • proxy-based AOP에서는 proxy를 통과하는 외부 호출만 advice가 적용된다.
  • self-invocation은 기본적으로 advice가 적용되지 않는다.
  • Spring은 AOP의 대표적 용도로 declarative transaction 같은 cross-cutting concern을 든다.
  • pointcut은 더 작은 named pointcut으로 조합하는 것이 권장된다.
  • 대부분의 경우 static pointcut이 충분하고 더 낫다.

기본 규칙

1. AOP는 cross-cutting concern에만 사용

다음은 AOP 후보가 된다.

  • 공통 로깅
  • 메트릭/트레이싱
  • 권한 체크의 반복 경계
  • 재시도/타이밍 측정
  • 공통 감사(audit)
  • 선언적 트랜잭션

다음은 AOP로 풀지 않는다.

  • 핵심 비즈니스 흐름
  • 상태 전이 정책
  • 도메인 규칙
  • 복잡한 분기 로직
  • 외부 API orchestration

2. 기본값은 “명시적 코드”, 예외적으로 AOP

같은 기능을 명시적 코드로 더 잘 읽을 수 있으면 AOP를 쓰지 않는다.

기본:

  • use case/service 안에서 명시적으로 보이는 흐름 우선
  • 반복되는 횡단 관심사만 AOP로 추출

3. proxy-based 한계를 항상 전제로 한다

Spring AOP는 proxy 기반이므로 다음을 전제로 설계한다.

  • proxy를 통과하는 외부 호출만 interception
  • self-invocation은 적용되지 않음
  • “같은 클래스 안에서 호출되면 aspect가 붙겠지”를 금지

4. self-invocation 해결을 위해 AOP 남용 금지

self-invocation 문제를 해결하려고 다음을 기본 금지한다.

  • 자기 자신 proxy 주입
  • AopContext.currentProxy() 의존
  • 구현을 proxy semantics에 강하게 묶는 설계

기본 대응:

  • 경계를 다시 분리
  • 클래스를 분리
  • 더 명시적인 구조로 변경

5. AOP는 경계가 뚜렷한 곳에만 적용

좋은 적용 지점:

  • service/use-case public method
  • controller 경계
  • repository 경계
  • 명시된 package/bean naming convention

지양:

  • 너무 넓은 전체 패키지
  • “일단 다 잡고 보자” 식 표현식
  • private/internal 세부 구현까지 얽는 pointcut

6. pointcut은 작고 이름 있게 조합

공식 권장대로 pointcut은 작은 named pointcut을 조합해 만든다.

기본:

  • package 범위 pointcut
  • role 기반 pointcut
  • public method pointcut
  • bean naming 기반 pointcut

를 분리하고 조합한다.

7. 대부분 static pointcut 우선

동적 조건보다 static pointcut이 충분하면 static 쪽을 우선한다. 성능/이해도/예측 가능성이 더 좋다.

8. @Around는 최소화

@Around는 가장 강력하지만 가장 위험하다. 반환값/예외/호출 자체를 제어할 수 있으므로 꼭 필요할 때만 쓴다.

기본 우선순위:

  • 단순 전처리 -> @Before
  • 정상 반환 후 후처리 -> @AfterReturning
  • 예외 기록/번역 -> @AfterThrowing
  • 무조건 정리 -> @After
  • 호출 제어/타이밍/재시도 등 정말 필요할 때만 @Around

9. advice 안에서 비즈니스 의미를 새로 만들지 않는다

advice는 보조 concern을 수행해야 한다.

금지:

  • 상태 전이 결정
  • 비즈니스 실패를 성공처럼 바꾸기
  • 핵심 정책 우회
  • controller/service가 해야 할 결정을 aspect에서 대신하기

10. 예외를 숨기지 않는다

AOP에서 예외를 잡더라도 기본은:

  • 기록
  • 문맥 추가
  • 그대로 전파 중 하나다.

금지:

  • 예외 삼키기
  • 정상값으로 은폐
  • 실패를 조용히 무시

11. 트랜잭션 대체 수단으로 일반 AOP를 남용하지 않는다

선언적 트랜잭션은 Spring이 제공하는 표준 메커니즘을 우선 사용한다. 일반 custom aspect로 transaction semantics를 흉내 내지 않는다.

12. AOP는 observability / policy enforcement에 더 적합

프로젝트에서 AOP는 아래 유형에 더 적합하다.

  • 실행 시간 측정
  • 공통 로깅
  • 감사 기록
  • annotation 기반 정책 강제
  • 공통 예외 기록

복잡한 use case orchestration에는 부적합하다.

13. pointcut 범위는 문서화 가능해야 한다

pointcut을 보고 아래를 설명할 수 있어야 한다.

  • 어디에 적용되는가
  • 왜 거기에만 적용되는가
  • 새 코드가 추가되면 어떤 naming/package 규칙으로 포함되는가

설명하기 어려우면 범위가 너무 넓거나 모호한 것이다.

14. bean naming / package convention을 설계와 함께 쓴다

Spring 공식 문서가 bean PCD나 package 기반 pointcut 예시를 드는 것처럼, AOP를 쓸 거면 package 구조나 bean naming convention이 일정해야 한다.

즉:

  • *Service
  • ..application..
  • ..infrastructure.. 같은 규칙은 pointcut과 함께 관리한다.

프로젝트 기준 요약

  • AOP는 cross-cutting concern에만 사용
  • 기본값은 명시적 코드
  • Spring AOP는 proxy-based라는 점을 전제로 설계
  • self-invocation 기대 금지
  • pointcut은 작고 이름 있게 조합
  • 대부분 static pointcut 우선
  • @Around 최소화
  • advice에서 비즈니스 의미를 만들지 않음
  • 예외를 숨기지 않음