Spring AOP와 트랜잭션 순서 설정하기

Spring에서 AOP(AspectJ)와 트랜잭션이 동시에 적용될 때 실행 순서를 제어하는 방법입니다. @Order 어노테이션과 Ordered 인터페이스를 활용합니다.

1. 문제 상황

로깅 AOP가 트랜잭션보다 먼저 실행되면 트랜잭션 밖에서 로깅되어 롤백 시 잘못된 로그가 남을 수 있습니다.

// 원하는 순서: 트랜잭션 시작 → 로깅 → 비즈니스 로직 → 로깅 → 트랜잭션 종료
// 잘못된 순서: 로깅 → 트랜잭션 시작 → 비즈니스 로직 → 트랜잭션 종료 → 로깅

2. @Order 어노테이션 사용

@Aspect
@Component
@Order(1)  // 숫자가 낮을수록 먼저 실행 (외부)
public class LoggingAspect {
    
    @Around("execution(* com.example.service.*.*(..))")
    public Object logAround(ProceedingJoinPoint pjp) throws Throwable {
        log.info("메서드 시작: {}", pjp.getSignature());
        Object result = pjp.proceed();
        log.info("메서드 종료: {}", pjp.getSignature());
        return result;
    }
}

@Aspect
@Component
@Order(2)  // LoggingAspect 다음에 실행 (내부)
public class SecurityAspect {
    // ...
}

3. 트랜잭션 순서 설정

@Configuration
@EnableTransactionManagement(order = 0)  // 가장 먼저 (가장 바깥)
public class TransactionConfig {
    // ...
}

// 또는 XML 설정
<tx:annotation-driven order="0"/>

4. 실행 순서 예시

// Order 값: 트랜잭션(0) → 로깅(1) → 보안(2)

트랜잭션 시작  ─┐
  로깅 시작    ─┤
    보안 체크  ─┤
      비즈니스 로직
    보안 체크  ─┘
  로깅 종료    ─┘
트랜잭션 커밋  ─┘

5. Ordered 인터페이스 구현

@Aspect
@Component
public class LoggingAspect implements Ordered {
    
    @Override
    public int getOrder() {
        return 1;
    }
    
    // ...
}

6. 실전 권장 순서

OrderAspect용도
0Transaction트랜잭션 관리 (가장 외부)
1Logging메서드 진입/종료 로깅
2Security권한 검사
3Validation입력값 검증
4Caching캐시 처리

7. 주의사항

  • Order 값이 같으면 실행 순서 보장 안 됨
  • @Order는 Spring Bean에만 적용
  • Lowest값(Integer.MAX_VALUE)이 가장 마지막 실행
  • Aspect끼리만 순서 조절, 일반 빈은 별도

8. 디버깅 팁

// 현재 적용된 AOP 순서 확인
@Autowired
private AspectJProxyFactory factory;

// 로그 레벨 설정
logging.level.org.springframework.aop=DEBUG
logging.level.org.springframework.transaction=DEBUG