[Spring] Proxy (2) Spring with proxy

rin·2020년 6월 4일
1
post-thumbnail

Spring with proxy

ref. https://do-study.tistory.com/83

스프링은 프록시 기반의 AOP를 제공하며, 이를 구현하기 위해 Java Dynamic Proxy를 사용하거나 Cglib을 사용한다.

  • AopProxy 라는 Delegator 인터페이스로 표현되며
    • Dynamic Proxy 기반은 JdkDynamicAopProxy 클래스
    • Cglib 기반은 CglibAopProxy 클래스이다.
  • Dynamic Proxy 기반과 Cglib 기반은 프록시 객체를 생성하는 방식에 차이가 있다.
    • Dynamic Proxy는 프록시 객체생성을 위해 인터페이스를 필수로 구현
    • Cglib은 인터페이스를 구현하지 않은 일반 클래스에 런타임 시 코드 조작으로 프록시 객체를 생성한다.
  • DefaultAopProxyFactory 클래스의 createAopProxy 메소드를 통해 AopProxy의 실 구현체가 생성된다.
    • AOP 적용 대상이 인터페이스거나 인터페이스를 구현하고 있으면 jdkDynamicAopProxy가 생성된다.
    • 그렇지 않으면 ObjenesisCglibAopProxy 기반 실 객체가 생성된다.
    • Objenesis : 과거 Cglib의 몇 가지 단점을 해결주는 라이브러리
  • Transaction 대상의 경우 기본적으로 Cglib으로 생성하게 설정되어있다.
    • 성능상 Cglib이 이점이 많고, 예외발생 확률도 적다고 한다.
    • Cglib이 가지고 있던 몇 가지 문제점들을 Objenesis 라이브러리가 해결 (생성자 중복 호출, default 생성자 필요 문제 등)
  • 기본 Spring AOP 이외에 스프링에서 사용할 수 있는 방법으로는 AspectJ가 있다.
  • Spring AOP가 제공하는 프록시 기반 방식은 "런타임 위빙(RTW)"이라는 방식 - 프로그램 구동 중에 위빙(코드삽입)이 일어난다.
    • 반면, AspectJ는 "컴파일 위빙(CTW)" 또는 "로드 타임 위빙(LTW)"을 이용하는데 이는 RTW 보다 성능이 우세하다.
    • 또한 AspectJ는 기본 Spring AOP 보다 다양한 포인트컷을 지원한다.
  • 일반적인 경우 Spring AOP에서 지원하는 방식으로 요구사항들이 충분히 해결되는 경우가 많고, 성능 또한 @AspectJ 갯수에 따라 달라진다. - 일반적인 경우에서는 크게 체감하기 힘들다고한다.
  • AspectJ를 사용하기 위해서는 AJC 등 별도의 컴파일러 설정 등 추가적인 설정이 필요하나 Spring AOP는 그렇지 않다.

스프링의 ProxyFactoryBean

ProxyFactoryBean는 프록시를 생성해 Bean 객체로 등록하게 해주는 팩토리 빈이다. TxProxyFacotryBean과는 달리 순수하게 프록시를 생성하는 작업만을 담당하며 프록시를 제공해줄 부가기능은 별도의 빈에 둘 수 있다. 부가기능의 경우 InvocationHandlerinvoke()와 달리, MethodInterceptor를 사용하여 타깃 오브젝트에 대한 정보를 함께 제공한다. 이를 통해 타깃 오브젝트에 상관없이 독립적으로 만들어 싱글톤 빈으로 등록 가능하다.

❗️ TransactionProxyFactoryBean
단순화된 선언적 트랜잭션 처리를 위한 프록시 팩토리 빈. 별도의 TransactionInterceptor 정의가 있는 표준 AOP ProxyFactoryBean의 편리안 대안책이다.

이 클래스는 원래 선언적인 트랜잭션 demarcation의 대표적인 사례, 즉 싱글톤 대상 객체를 트랜잭션 프록시로 감싸고 타켓이 구현하는 모든 인터페이스를 프록시 처리하도록 설계되었다. 하지만 스프링 2.0 버전 이상부터 이 기능들은 좀 더 편리한 tx: XML 네임스페이스로 대체되었다.

proxy와 Bean

Spring에서 Bean으로 등록된 객체는 싱글톤으로 등록돼 IoC 컨테이너에서 관리된다. Bean 객체에 대해 Spring AOP를 적용하는 경우에는 Proxy가 생성되는데, Bean을 DI하는 곳에서는 어떻게 Proxy를 주입하여 사용할까?

스프링은 빈 후처리기에서 자동으로 프록시를 생성하기 위해 DefaultAdvisorAutoProxyCreator라는 클래스를 사용한다. 이 클래스는 어드바이저를 이용한 자동 프록시 생성기이다. 이를 이용하여 빈 오브젝트의 일부를 프록시로 포장하고, 프록시를 빈으로 대신 등록시킬 수 있다.

즉, DefaultAdvisorAutoProxyCreator이 빈 후처리기로 등록되어있다면 다음과 같이 프록시가 빈 오브젝트를 대체하도록 만든다.

  1. 스프링은 빈 오브젝트를 만들 때마다 후처리기에 빈을 보낸다.
  2. 후처리기는 빈으로 등록된 모든 어드바이저 내의 포인트 컷을 이용해 전달받은 빈이 프록시 적용 대상인지 확인한다.
  3. 프록시 적용 대상이면 내장된 프록시 생성기를 통해 현재 빈에 대한 프록시를 생성하고 어드바이저를 연결한다.
  4. 프록시가 생성되면 전달받은 타겟 빈 오브젝트 대신에 프록시 오브젝트를 스프링 컨테이너에 돌려준다.
  5. 컨테이너는 빈 후처리기가 돌려준 프록시 오브젝트를 빈으로 등록한다.

이 후처리기 덕에 일일이 ProxyFactoryBean으로 등록하지 않아도 여러 타깃 오브젝트에 자동으로 프록시를 적용시킬 수 있다.

profile
🌱 😈💻 🌱

0개의 댓글