스프링 프레임워크(Spring Framework) 톺아보기 - 스프링이 지원하는 프록시

Janek·2023년 3월 4일
0

Spring 톺아보기

목록 보기
10/10
post-thumbnail

해당 포스팅은 인프런에서 제공하는 김영한 님의 '스프링 핵심원리 고급편'을 수강한 후 정리한 글입니다. 유료 강의를 정리한 내용이기에 제공되는 예제나 몇몇 내용들은 제외하였고, 정리한 내용을 바탕으로 글 작성자인 저의 언어로 다시 작성한 글이기에 서술이 부족하거나 잘못된 내용이 있을 수 있습니다. 그렇기에 해당 글은 개념에 대한 참고 정도만 해주시고, 강의를 통해 학습하시기를 추천합니다.

프록시 팩토리

동적 프록시 사용의 문제점

동적 프록시를 사용할 때 인터페이스가 있는 경우에는 JDK 동적 프록시를, 구체 클래스는 CGLIB를 적용해야 한다. 이를 자동화할 수 있는 방법이 필요하며, 이 때 JDK 동적 프록시가 제공하는 InvocationHandler와 CGLIB가 제공하는 MethodInterceptor를 각각 중복으로 개발하여 관리해야 하는지, 특정 조건에 부합할 때 프록시 로직을 적용하는 공통 기능 제공 등 고민해야 할 부분이 존재한다.

프록시 팩토리

스프링은 유사한 구체적인 기술들이 존재할 때 이를 통합해서 일관성 있게 접근하고 편리하게 사용할 수 있도록 추상화된 기술을 제공하며, 동적 프록시를 통합해서 관리하기 위해 프록시 팩토리(ProxyFactory)를 제공한다.

프록시 팩토리를 사용할 경우 인터페이스는 JDK 동적 프록시를, 구체 클래스만 존재할 경우 CGLIB를 사용한다. 또한 이 설정을 변경할 수도 있게 해준다.

Advice

또한 두 기술을 함께 사용할 때 부가 기능을 적용하기 위해 각 기술을 중복해서 개발하지 않도록 Advice라는 새로운 개념을 도입했다.

개발자는 InvocationHandlerMethodInterceptor를 구분하지 않고 Advice 하나만을 만들면 프록시 팩토리가 기술에 맞게 해당 Advice를 호출하는 전용 InvocationHandlerMethodInterceptor를 내부적으로 사용한다.

Advice 구현 및 프록시 팩토리 적용

Advice를 만드는 방법은 기본적으로 스프링 AOP 모듈에서 제공하는 org.aopalliance.intercept 패키지의 MethodInterceptor를 구현하면 된다.

public class TestAdvice implements MethodInterceptor {
	
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
    	System.out.println("TestProxy Run");
        
        Object result = invocation.procced();	
        /* 
         * target 클래스 호출 및 결과 반환
         * target 클래스의 정보는 MethodInvocation 안에 모두 포함,
         * ProxyFactory를 생성하는 단계에 이미 target 정보를 파라미터로 전달
         */
        
        System.out.println("TestProxy Stop");
        return result;
    }
    
}

public class ProxyFactoryTest {

	public void interfaceProxy() {	// JDK 동적 프록시 적용
    	TestInterface target = new TestInterface();
        ProxyFactory proxyFactory = new ProxyFactory(target);
        // target 정보를 파라미터로 전달받는다.
        proxyFactory.addAdvice(new TestAdvice());
        
        TestInterface proxy = (TestInterface) proxyFactory.getProxy();
        
        proxy.execute();
    }

	public void concreteProxy() {	// CGLIB 적용
    	TestClass target = new TestClass();
        ProxyFactory proxyFactory = new ProxyFactory(target);
        // target 정보를 파라미터로 전달받는다.
        proxyFactory.addAdvice(new TestAdvice());
        
        TestClass proxy = (TestClass) proxyFactory.getProxy();
        
        proxy.execute();
    }
    
	public void interfaceProxyTargetClass() {	
    // Interface가 존재하지만 CGLIB 적용
    	TestInterface target = new TestInterfaceImpl();
        ProxyFactory proxyFactory = new ProxyFactory(target);
        // target 정보를 파라미터로 전달받는다.
        proxyFactory.setProxyTargetClass(true);	// 구현체에 적용
        proxyFactory.addAdvice(new TestAdvice());
        
        TestInterface proxy = (TestInterface) proxyFactory.getProxy();
        
        proxy.execute();
    }
    
}

Pointcut

스프링은 Pointcut이라는 개념을 도입해 특정 조건에 부합할 경우에만 프록시 부가 기능이 적용되도록 설정해줄 수 있게 해준다.

Pointcut, Advice, Advisor

프록시 팩토리는 역할과 책임을 명확하게 분리하기 위해 다음과 같은 단어들을 사용한다.

  • Pointcut : 프록시 부가 기능을 적용할지 여부를 판단하는 필터링 로직. 주로 클래스와 메서드 이름으로 필터링 한다.
  • Advice : 프록시가 호출하는 부가 기능. 프록시 로직
  • Advisor : 하나의 포인트컷과 하나의 어드바이스를 포함한 개념
profile
만들고 나누며, 세상을 이롭게 하고 싶습니다.

0개의 댓글