
AOP는 '메서드 앞뒤로 특정 기능을 끼워 넣는 기술'
ex)
이런 부가 기능을 자동으로 넣을 수 있게 해주는 것이 AOP
그럼 이걸 어떻게 넣을까?
-> 스프링이 '프록시 객체'를 만들어준다.
프록시는 '원래 객체를 대신해서 앞에 선 대리인 같은 존재'
ex)
[내 코드] → OrderService.order()
↓
[스프링 프록시] → (부가기능 : 로그/트랜잭션) → 실제 OrderService.order() 실행
내 코드는 OrderService를 호출한다고 생각하지만, 사실은 Proxy가 가로채서 부가기능을 실행한 후에 원본 실행
1. @Transactional 같은 AOP 어노테이션 확인
2. 원본 객체 대신 프록시 객체 생성
3. 메서드 호출을 프록시가 가로챔
4. 부가 기능 실행 후 실제 메서드 호출
스프링이 컴포넌트 스캔할 때 '이 클레스에는 AOP 어노테이션이 붙어있네?'라고 판단
스프링은 2가지 방식 중 하나로 프록시를 생성
그 결과 컨테이너에는 원본이 아니라 프록시가 등록됨
JDK Proxy = '인터페이스가 있으면 인터페이스를 흉내내어 프록시 생성'
CGLIB = '인터페이스가 없으면 클래스를 상속하여 프록시 생성'
public interface PaymentService {
void pay();
}
@Service
public class PaymentServiceImpl implements PaymentService {
public void pay() { ... }
}
@Service
public class OrderService {
public void order() { ... }
}
public class OrderServiceProxy extends OrderService {
@Override
public void order() {
// 부가 기능
super.order();
}
}
| 구분 | JDK Dynamic Proxy | CGLIB Proxy |
|---|---|---|
| 기반 | 인터페이스 | 클래스 상속 |
| 인터페이스 필요 조건 | 있어야 한다 | 없어도 된다 |
| 생성 방식 | 인터페이스 구현 객체 생성 | 원본 클래스를 상속한 서브클래스 생성 |
| 제한 | 인터페이스 없으면 생성 X | final 클래스/메서드 못 감쌈 |
| 속도 | 좀 더 가벼움 | 상대적으로 무거움 |
내 코드가 호출하는 대상은 이미 프록시
내 코드 -> Proxy.order() -> (AOP 기능 실행) -> 실제 order() 실행
ex) @Transactional
Proxy : 트랜잭션 시작
↓
원본 메서드 호출
↓
정상 종료 : 커밋
예외 발생 : 롤백