Home Spring AOP(2)
Post
Cancel

Spring AOP(2)

ProxyFactory

org.springframework.aop.framework.ProxyFactory 설명하기 앞서 Spring에서 AopProxy를 어떤 식으로 관리하는지 살펴 보겠습니다.

1
2
3
4
5
6
7
8
9
public interface AopProxy {

	Object getProxy();

	Object getProxy(@Nullable ClassLoader classLoader);

	Class<?> getProxyClass(@Nullable ClassLoader classLoader);

}

스프링은 org.springframework.aop.framework.AopProxy를 통해 AOP Proxy 객체를 추상화했습니다.
그 중 제공하는 구현체로는 인터페이스 기반의 JDK Dynamic Proxy와 클래스 & 인터페이스 기반의 CGLIB 프록시가 있습니다.

cglib-aop-proxy

jdk-dynamic-aop-proxy

AopProxygetProxy() 메소드를 통해 각 구현체의 전략에 따라 프록시 객체에 접근할 수 있습니다.

Spring은 org.springframework.aop.framework.AopProxyFactory 인터페이스를 통해서 위와 같은 AopProxy를 생성하고 접근합니다. 기본 구현체로는 DefaultAopProxyFactory를 가지고 있습니다.

1
2
3
4
public interface AopProxyFactory {

	AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;
}

기본 구현체인 DeafultAopProxyFactory는 매개변수로 전달받는 ProxyConfig를 구현한 org.springframework.aop.framework.AdvisedSupport 클래스를 통해 대상 클래스의 프록시를 생성합니다.

proxy-factory

위와 같은 기능들을 제공해주기 위해 스프링은 ProxyFactory를 제공하며 구성 가능한(configurable) AopProxyFactory에 대한 편리한 액세스를 제공하는 ProxyCreatorSupport가 프록시 객체를 생성하고 실제 AopProxy에 접근합니다.

동작 방식

먼저 동작 방식을 확인하기 위해 프록시 대상 클래스인 인터페이스를 구현한 SampleService클래스를 생성합니다.

sample-service

그 후 대상 클래스에 적용될 Advisor를 AopFactory에 설정합니다.

sample-service-test

위와 같이 설정을 완료 한 후 코드를 실행하여 ProxyFactory에서 어떤 식으로 프록시를 생성하며 사용하는지 확인해보겠습니다.

먼저 ProxyFactory 객체를 생성하면서 대상 객체를 등록합니다.

proxy-factory-construct

두번째로 Advisor를 등록합니다. Advisor는 Pointcut과 Advice가 저장되어 있는 객체로 한쌍으로 이루어져있습니다. 또한 ProxyFactory는 내부적으로 Advisor를 리스트로 관리합니다. 즉 복수개의 Advisor를 등록할 수 있으며 등록한 순서대로 Advisor를 처리합니다.

add-advisor

설정 및 생성이 끝났다면 ProxyFactorygetProxy() 메소드를 통해 설정에 따라 새로운 프록시를 생성합니다.

get-proxy

getProxy() 메소드를 호출하게 되면 먼저 AdvisedSupport 설정 클래스를 통해 AopProxy를 생성하게 됩니다. AdvisedSupport에 설정된 내용을 통해서 createAopProxy()는 JDK Dynamic Proxy 또는 CGLIB 2가지 타입 중 적절한 프록시를 생성하여 반환합니다.

create-aop-proxy

JDK Dynamic Proxy는 Proxy.newProxyInstance()로 프록시를 생성하고

jdk-get-proxy

CGLIB는 Enhancer 객체를 통해 프록시를 생성합니다.

cglib-get-proxy

각 타입에 맞게 생성된 프록시는 대상 객체의 메소드를 위임 받아 실행시키는데 ProxyFactory에 등록된 Advisor들의 Adivce Chain 형태로 실행시킵니다. 체인 형태로 실행시키기 전에 ProxyFactoryAdvisedSupport는 들고 있는 Advisor List를 통해 ProxyChain을 구성합니다. ProxyChain에 구성된 Advice들은 프록시 객체를 통해 호출되며 이때 Advice들을 실행하고 원본 메소드를 호출하고 적용되는 순서와 방식을 관리합니다.

AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice() 메소드를 통해서 ProxyChain를 가져옵니다. Advisor 리스트에 있는 Pointcut을 비교한 뒤 일치하는 MethodInterceptor(ProxyChain)를 추가합니다.

jdk-proxy-chain

internal-proxy-chain

그 후 생성된 MethodInvocation은 ProxyChain을 순회하면서 invoke() 메소드를 통해 Advice를 실행합니다.

jdk-invocation

invoke

정리

Spring AOP는 AopProxy를 추상화하여 관리하고 있으며 구현체로는 JDKDynamicAopProxy와 CGLIBAopProxy가 있습니다. JDKDynamicAopProxy Reflection을 이용해 프록시 객체를 생성하고 CGLIBAopProxy는 Enhancer 라이브러리를 통해 바이트 코드를 조작하여 생성합니다. 또한 두개 프록시의 차이로는 JDKDynamicAopProxy는 인터페이스 대상 객체만을 프록시로 생성할 수 있으며 CGLIBAopProxy는 클래스 대상 객체를 프록시로 생성할 수 있습니다.

또한 Spring은 두개의 AopProxy를 생성할 수 있는 AopProxyFactory를 제공하며 ProxyFactory의 부모 클래스인 ProxyCreatorSupport를 통해 ProxyFactory는 AopProxy 객체를 생성하고 접근하고 관리합니다.

ProxyFactory는 대상 객체와 여러 개의 Advisor를 통해 생성되며 이 여러 개의 Advisor는 ProxyChain으로서 Pointcut이 매칭되는 대상 객체를 Advice를 합니다. 메소드 체이닝이 끝나면 프록시 객체는 대상 객체의 메소드를 실행하며 실행이 끝난 후 매칭되는 ProxyChain의 Advice가 실행되며 메소드 실행 사이클이 종료됩니다.

오탈자 및 오류 내용을 댓글 또는 메일로 알려주시면, 검토 후 조치하겠습니다.