본문 바로가기
프레임워크/Spring

Spring AOP Proxy

by 프로그래밍 공부 2023. 4. 12.

 지난 번에는 Spring AOP에 대해 알아 보았다.

그렇다면 이번에는 Spring AOP가 동작하는 매커니즘에 대해 알아보자.

작성한 AOP가 실행되는 과정에서 Spring AOP는 JDK dynamic proxy나 CGLIB proxy를 사용해 

Advice가 적용된 Proxy 객체를 호출하게 된다. 

즉, 실제 기능이 구현된 Target 객체를 호출하면, Target이 호출되는것이 아니라 

Advice가 적용된 Proxy 객체가 호출되는 것이다. 

8.6 Proxying mechanisms (spring.io)

 

8.6 Proxying mechanisms

Spring AOP uses either JDK dynamic proxies or CGLIB to create the proxy for a given target object. (JDK dynamic proxies are preferred whenever you have a choice). If the target object to be proxied implements at least one interface then a JDK dynamic proxy

docs.spring.io

 

위의 문서를 읽어보면 Spring AOP는 Proxy를 생성하고 작성한 AOP 클래스를 핸들링하게 된다.

결국 Proxy는 대행자라고 생각하면 된다.

일반적으로 객체를 생성해서 함수를 호출 할 때는 위와 같이 이뤄지는 데에 반해,

Proxy를 통해 함수를 호출할 때는 위와 같이 작동한다. 

둘의 차이는 다음과 같다.

public class Main{
	public static void main(String[] args){
    	Pojo pojo = new SimplePojo();
        
        pojo.foo();
    }
}
//일반적으로 객체를 생성해 함수를 호출할 때


public class Main{
	public static void main(String[] args){
    	ProxyFactory factory = new ProxyFactory(new SimplePojo());
        factory.addInterface(Pojo.class);
        factory.addAdvice(new RetryAdvice());
        
        Pojo pojo = (Pojo) factory.getProxy();
        
        pojo.foo();
    }
}
//Proxy를 생성한 뒤 호출하려는 함수를 가지고 있는 객체의 클래스와 Advice를 추가한 후 
//해당 객체를 프록시를 통해 호출한 뒤 함수를 호출한다.

위의 코드에서 나오는 ProxyFactory 내의 메서드에 관해 알아보면

첫번째로 객체를 인자로 받는 생성자

받은 객체를 setTarget한다.

setTarget 메서드는 위와 같다. 

받은 객체를 SingletonTargetSource라는 생성자로 전달한 뒤, 이를 setTargetSource 메서드로 받는다.

SingletonTargetSource 생성자는 받은 객체가 null인지 확인하고 null이 아니라면 target Instance에 할당하는 생성자이다.

setTargetSource 메서드는 null일 수 있는 TargetSource를 받아서 

targetsource Instance에

해당 인자가 null이 아니라면 targetSource로

null이라면 EMPTY_TARGET_SOURCE로 할당하는 메서드이다.

즉, 최초 Proxy 생성할 때, 함수 호출할 객체를 인자로 받아서 인자가 null인지 아닌지 확인 후 Target으로 할당하는 것이다.

그 다음으로는 setInterfaces 메서드를, 또 그 안에는 ClassUtils 내의 getAllInterfaces 메서드를 호출하는데

getAllInterfaces 메서드는 받은 인자를 똑같이 null여부를 확인 후, 해당 인스턴스의 클래스를 

getAllInterfacesForClass 메서드로 받은 후 return 하는 것이다. 

getAllInterfacesForClass 메서드는 받은 인자가 구현하는 모든 인터페이스를 반환하는 것이다. 

add Interface 메서드는 받은 인자가 인터페이스인지 확인한 후 추가를 해주는 메서드이고,

addAdvice 메서드는 받은 인자를 addAdvice(int 자료형, Advice 자료형) 메서드로 넘겨주는 역할이다.

addAdvice 메서드가 넘겨 받으면 null인지를 확인 후 해당 advice 타입에 따라 addAdvisor 메서드를 호출하거나, 

예외를 던지기도 한다. 

 

 

무척이나 복잡하지만 

프록시를 생성할 때 객체를 받은 후, 

받은 객체의 null 여부 확인, 

객체의 클래스가 Interface인지, 또 null인지 여부 확인

받은 Advice의 타입 확인 등의 절차가 이뤄지는 것이다.

그 후

프록시 팩토리 메서드인 getProxy를 통해 객체를 생성해 함수를 호출하게 되는데

active라는 boolean 타입 변수를 true로 변환해주고,

ProxyCreatorSuport 클래스 내에 final 변수인 ArrayList<AdvisedSupportListener> listeners 에 들어있는 

listener를 활성화해준다.

 

 

너무 어렵다.

간단하게

위 이미지를 다시 보고 요약하면

객체를 프록시팩토리로 전달후, 

객체 null 체크 Interface 체크 advice 체크

후 프록시에 감싸진 객체를 선언한 뒤 

해당 객체를 통해 함수를 호출하게 되는 것이다.

 

 

 

라고 이해했다. 추후 더 알게되면 수정할 것