[TIL] 프록시 팩토리 = (JDK 동적프록시 + CGLIB)

SlowAnd·2024년 1월 3일
0

Today I Learned

목록 보기
10/17
post-thumbnail

[이전 학습 내용]- 리플렉션,프록시,JDK 다이나믹 프록시, CGLIB

기존 동적 프록시( JDK 다이나믹 프록시, CGLIB) 의 문제

Q: 인터페이스가 있는 경우에는 JDK 동적 프록시를 적용하고, 그렇지 않은 경우에는 CGLIB를 적용하려면 어떻게 해 야할까?

프록시 팩토리

스프링은 동적 프록시를 통합해서 편리하게 만들어주는 프록시 팩토리( ProxyFactory )라는 기능을 제공한다.

프록시 팩토리는 인터페이스가 있으면 JDK 동적 프록시를 사용하고, 구체 클래스만 있다면 CGLIB를 사용한다. 그리고 이 설정을 변경할 수도 있다.

프록시 팩토리 - 의존관계

프록시 팩토리 - 사용 흐름

Q: 두 기술을 함께 사용할 때 부가 기능을 적용하기 위해 JDK 동적 프록시가 제공하는 InvocationHandler와 CGLIB가 제공하는 MethodInterceptor를 각각 중복으로 따로 만들어야 할까?

스프링은 이 문제를 해결하기 위해 부가 기능을 적용할 때 Advice 라는 새로운 개념을 도입했다. 개발자는InvocationHandlerMethodInterceptor 를 신경쓰지 않고, Advice 만 만들면 된다.
결과적으로 InvocationHandlerMethodInterceptorAdvice 를 호출하게 된다.
프록시 팩토리를 사용하면 Advice 를 호출하는 전용 InvocationHandler , MethodInterceptor 를 내부에서 사용한다.

Advice 도입



Q: 특정 조건에 맞을 때 프록시 로직을 적용하는 기능도 공통으로 제공되었으면?
앞서 특정 메서드 이름의 조건에 맞을 때만 프록시 부가 기능이 적용되는 코드를 직접 만들었다. 스프링은 Pointcut 이라는 개념을 도입해서 이 문제를 일관성 있게 해결한다.

Advice 만들기

Advice 는 프록시에 적용하는 부가 기능 로직이다.
이것은 JDK 동적 프록시가 제공하는 InvocationHandler
CGLIB가 제공하는 MethodInterceptor 의 개념과 유사한다.
둘을 개념적으로 추상화 한 것이다.
프록시 팩토리를 사용하면 둘 대신에 Advice 를 사용하면 된다.

Advice 를 만드는 방법은 여러가지가 있지만, 기본적인 방법은 다음 인터페이스를 구현하면 된다.

스프링이 제공하는 MethodInterceptor

CGLIB의 MethodInterceptor 와 이름이 같으므로 패키지 이름에 주의하자.

  • 참고로 여기서 사용하는 org.aopalliance.intercept 패키지는 스프링 AOP 모듈( spring-aop ) 안에 들어있다.

TimeAdvice 는 앞서 설명한 MethodInterceptor 인터페이스를 구현한다. 패키지 이름에 주의하자. Object result = invocation.proceed()
invocation.proceed() 를 호출하면 target 클래스를 호출하고 그 결과를 받는다.
그런데 기존에 보았던 코드들과 다르게 target 클래스의 정보가 보이지 않는다.
(JDK 동적 프록시, CGLIB 전부 인자값으로 target 정보를 넣어줬었다..)

target 클래스의 정보 는 MethodInvocation invocation 안에 모두 포함되어 있다.
그 이유는 바로 다음에 확인할 수 있는데, 프록시 팩토리로 프록시를 생성하는 단계에서 이미 target 정보 를 파라미터로 전달받기 때문이다.

1. JDK 적용된 테스트 코드

결과

2. CGLIB 적용된 테스트 코드

결과

프록시 팩토리의 기술 선택 방법

프록시 팩토리의 기술 선택 방법

  • 대상에 인터페이스가 있으면: JDK 동적 프록시, 인터페이스 기반 프록시
  • 대상에 인터페이스가 없으면: CGLIB, 구체 클래스 기반 프록시
  • proxyTargetClass=true : CGLIB, 구체 클래스 기반 프록시, 인터페이스 여부와 상관없음

정리

정리

  • 프록시 팩토리의 서비스 추상화 덕분에 구체적인 CGLIB, JDK 동적 프록시 기술에 의존하지 않고, 매우 편리하게 동적 프록시를 생성할 수 있다.
  • 프록시의 부가 기능 로직도 특정 기술에 종속적이지 않게 Advice 하나로 편리하게 사용할 수 있었다. 이것은 프 록시 팩토리가 내부에서 JDK 동적 프록시인 경우 InvocationHandlerAdvice 를 호출하도록 개발해두 고, CGLIB인 경우 MethodInterceptorAdvice 를 호출하도록 기능을 개발해두었기 때문이다.

참고
스프링 부트는 AOP를 적용할 때 기본적으로 proxyTargetClass=true 로 설정해서 사용한다. 따라서 인터페이스가 있어도 항상 CGLIB를 사용해서 구체 클래스를 기반으로 프록시를 생성한다. 자세한 이유는 강의 뒷 부분에서 설명한다.

자료 참고
스프링 핵심 원리 - 고급편 - 인프런

0개의 댓글