-
JDK 동적 프록시는 인터페이스 기반의 프록시 제공
-
CGLIB 는 클래스 상속 기반의 프록시 제공
-
스프링에서 동적 프록시를 통합하여 프록시 팩토리 라는 기능을 제공
- 인터페이스가 있으면 JDK 동적 프록시를 사용하고, 구체 클래스만 있으면 CGLIB 를 사용
- InvocationHandler, MethodInterceptor 를 각각 중복으로 만들지 않도록 Advice 라는 개념 도입
- 개발자는 Advice 만 작성하여 부가기능을 만들 수 있음
- 또한 특정 조건을 만족할 때만 프록시 부가기능이 적용되도록 하는 Pointcut 개념을 도입함
-
Advice 는 기본적으로 MethodInterceptor 인터페이스(org.aopalliance.intercept.MethodInterceptor)를 구현하면 됨 (CGLIB 의 MethodInterceptor 와 다른 인터페이스임)
-
프록시 팩토리의 기술 선택 방법
- 대상 객체에 인터페이스가 있으면 JDK 동적 프록시, 인터페이스 기반 프록시 적용
- 대상 객체에 인터페이스가 없으면 CGLIB, 구체 클래스 기반 프록시 적용
- proxyTargetClass 옵션을 true로 전달하면 인터페이스 여부와 상관없이 CGLIB, 구체 클래스 기반 프록시 적용
-
프록시 팩토리의 서비스 추상화로 인해 구체적인 기술(CGLIB, JDK 동적 프록시)에 의존하지 않고 편리하게 동적 프록시를 생성할 수 있음
-
스프링 부트는 AOP 를 적용할 때 기본적으로 proxyTargetClass 를 true 로 설정하여 항상 CGLIB 를 사용해서 구체 클래스 기반으로 프록시를 생성함
-
포인트컷, 어드바이스, 어드바이저
- 포인트컷
- 어디에 부가 기능을 적용할지 판단하는 필터링 로직
- 주로 클래스와 메서드 이름으로 필터링
- 어드바이스
- 어드바이저
- 하나의 포인트컷과 하나의 어드바이스를 가지고 있는 객체
- 작동원리
- 클라이언트가 프록시 객체의 메서드 호출
- 포인트컷에서 호출한 메서드의 어드바이스를 적용할지 판단
- 포인트컷이 true 반환시 어드바이스를 호출하여 부가 기능을 적용하고 실제 인스턴스를 호출
-
스프링이 제공하는 포인트컷
- NameMatchMethodPointcut
- JdkRegexpMethodPointcut
- TruePointcut
- AnnotationMatchingPointcut
- AspectJExpressionPointcut
-
여러 어드바이저 함께 적용
- 기본적으로 어드바이저는 하나의 포인트컷과 하나의 어드바이스로 구성
- 부가 기능을 여러 개 적용하려면 프록시 객체를 여러개 만드는 방법 -> 프록시 객체를 어드바이저 수만큼 생성해야하는 단점
- 프록시 팩토리에 여러 개의 어드바이저를 등록하는 방법
- 스프링 AOP 는 하나의 타겟 객체에 여러 AOP 가 동시에 적용되어도 하나의 프록시 객체만 생성함
-
프록시 팩토리의 한계
- 프록시 팩토리를 통한 프록시 객체 생성 코드를 프록시 수 만큼 작성해야함
- 컴포넌트 스캔으로 프록시 적용이 불가능하고 수동으로 빈을 설정해야함