To Dare Is To Do!
Spring AOP 본문
1. AOP란?
AOP(Aspect-Oriented Programming, 관점 지향 프로그래밍)는 공통적으로 사용되는 횡단 관심사(Cross-Cutting Concern)를 핵심 비즈니스 로직과 분리하여 모듈화할 수 있도록 해주는 프로그래밍 패러다임이다.
- 핵심 관심사: 서비스 로직, 예: 회원가입, 주문 생성
- 횡단 관심사: 공통 기능, 예: 로깅, 보안, 트랜잭션, 성능 측정 등
2. AOP를 사용하는 이유
OOP만으로도 관심사를 분리할 수 있지만 다음과 같은 한계가 존재한다:
- 중복 코드 증가: 예를 들어 트랜잭션을 적용하려면 UserServiceTx, OrderServiceTx 등 중복 클래스를 생성해야 함
- 결합도 증가: 트랜잭션 기능을 적용하려면 구현 객체를 감싸는 방식으로 계층을 형성해야 하므로 클래스 간 의존도가 높아짐
- 유지보수 어려움: 모든 클래스마다 프록시 로직을 수동으로 적용해야 하므로 개발 및 테스트 비용 증가
- 세밀한 적용 어려움: 특정 메서드에만 공통 로직을 적용하기가 번거로움
=> AOP는 이와 같은 한계를 보완하여 공통 로직을 한 곳에 모아 관리하고, Pointcut을 통해 필요한 시점에 자동 적용할 수 있다.
3. 핵심 개념
- Aspect: 횡단 관심사를 모듈화한 클래스 (ex. @Aspect 클래스)
- JoinPoint: Advice가 실행될 수 있는 지점 (ex. 메서드 호출, 예외 발생 등)
- Pointcut: JoinPoint 중에서 실제 Advice가 적용될 지점을 선택하는 표현식
- Advice: 실제 실행될 횡단 로직 (ex. @Before, @After, @Around 등)
- Target Object: 핵심 기능을 수행하는 실제 객체
4. AOP 구현 방식
- 컴파일 시 삽입: AspectJ 사용 시, 컴파일 단계에서 바이트코드에 Advice 삽입 (Compile-Time Weaving)
- 클래스 로딩 시 삽입: 로딩 시점에 바이트코드를 조작해 삽입 (Load-Time Weaving)
- 런타임 프록시 방식: Spring AOP 방식. 프록시 객체를 생성해 호출 시점에 부가기능 삽입 (Runtime Weaving)
=> Spring AOP는 프록시 기반의 런타임 위빙 방식을 사용하며, 내부적으로 다음 두 가지 중 하나로 프록시를 생성한다:
- JDK Dynamic Proxy: 인터페이스 기반 프록시 (리플렉션 사용)
- CGLIB: 클래스 기반 프록시 (바이트코드 조작)
Spring은 대상 객체가 인터페이스를 구현하고 있으면 JDK 동적 프록시를, 아니면 CGLIB을 사용한다.
5. 프록시 동작 방식
- 클라이언트가 서비스 객체를 호출하면, 실제 대상이 아닌 프록시 객체가 응답한다.
- 프록시 객체는 먼저 Advice가 적용되어야 하는지 판단한다.
- 적용 대상이면 전처리 Advice(@Before 등)를 실행한다.
- 그 후 실제 Target Object의 메서드를 호출한다.
- 메서드 실행이 끝나면, 후처리 Advice(@AfterReturning, @AfterThrowing 등)를 실행한다.
- 결과를 클라이언트에게 반환한다.
=> 이 전체 흐름은 @Around Advice 하나로 통합 처리도 가능하다.
6. AOP 사용 시 주의사항
- 자기 자신의 메서드를 호출할 경우 AOP가 적용되지 않음
- 프록시를 통하지 않고 직접 호출하기 때문
- private, final 메서드에는 CGLIB 기반 AOP도 적용되지 않음
- @Transactional도 AOP 기반이므로 위 제약 조건 동일하게 적용됨
7. 적용 예시
@Aspect
@Component
public class LogAspect {
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethods() {}
@Before("serviceMethods()")
public void before(JoinPoint joinPoint) {
System.out.println("메서드 실행 전: " + joinPoint.getSignature());
}
}
8. 정리
구분 JDK Dynamic Proxy CGLIB
대상 | 인터페이스 | 클래스 |
방식 | 리플렉션 | 바이트 코드 조작 |
장점 | 설정 간편 | 성능 우수, 유연성 높음 |
단점 | 인터페이스 필수 | final 클래스/메서드 제한 |
9. AOP를 적용하면 좋은 사례
- 트랜잭션 처리 (@Transactional)
- 로깅
- 보안 검증
- 실행 시간 측정
- 캐시 적용
10. 결론
AOP는 OOP의 단점을 보완해 주는 보조적인 도구이며, 핵심 로직에 집중할 수 있도록 도와준다. Spring AOP는 런타임 프록시 방식을 채택하여 개발자가 손쉽게 횡단 관심사를 적용하고 관리할 수 있게 해준다.
'Spring' 카테고리의 다른 글
HTTP Status Code / Method (1) | 2024.07.02 |
---|---|
객체 지향 설계의 5가지 원칙(SOLID) (1) | 2023.12.23 |
DTO와 Entity의 변환 (0) | 2023.11.16 |
DTO vs VO vs Entity (0) | 2023.11.07 |
Spring 3계층 속 DI (0) | 2023.11.05 |