콘텐츠로 이동

2021 07 09

2021-07-09

토비의 Spring 6장. AOP

  • 복습 - 내가 정의한 객체에 비즈니스 로직이 아닌 "추가 기능"을 넣어주고 싶어 - 가령 트랜잭션 - 해당 객체를 생성자 파라미터로 받아서, 추가 처리가 필요한 메서드를 오버라이딩 해준 뒤 추가 로직 구현 - 이러면 프록시를 확실히 알아야하고, 매번 만들어줘야해 - 다이나믹 프록시 등장 - 부가 기능 가진 클래스의 존재 몰라야 해 - 데코레이터 패턴 - 타깃에 부가적인 기능을 런타임에 프록시를 통해 부여 - 다이나믹 프록시가 인터페이스 구현 클래스의 오브젝트 만들어 줌 - 프록시로서 필요한 부가기능 코드는 직접 작성할 것 - import java.lang.reflect.Proxy; - Proxy.newProxyInstance(클래스로더, 인터페이스 구현 클래스, InvocationHandler) - 팩토리 빈 등장 - 이렇게 만든 다이나믹 프록시 오브젝트는 스프링 빈으로 등록 X - FactoryBean<?>을 통해 팩토리 빈 만들기 - getObject()를 통해 필요한 오브젝트 뚝딱 나옴
    public class MessageFactoryBean implements FactoryBean<Message> {
        String text;
    
        public MessageFactoryBean(String text) { this.text = text; }
    
        @Override
        public Message getObject() { return Message.newMessage(text); }
    
        @Override
        public Class<?> getObjectType() { return Message.class; }
    
        @Override
        public boolean isSingleton() { return false; }
    }
    
  • 내가 정의한 프록시 팩토리 빈의 한계 - 타깃에 부가기능을 메서드 단위 별로 부여 - 한 번에 여러개의 클래스에 공통적인 부가기능 부여 불가 - 하나의 타깃에 여러개의 기능 부여도 어려움 - 프록시에 프록시에 프록시에 프록시를 더해서~
  • 6.4 스프링의 프록시 팩토리 빈 - 스프링은 일관된 방법으로 프록시를 만들어주는 추상 레이어 제공 - 생성된 프록시는 스프링의 빈으로 등록 - 스프링은 프록시 오브젝트를 생성해주는 기술을 추상화한 팩토리 빈 제공 - ProxyFactoryBean() - ProxyFactoryBean() - 프록시에서 사용할 부가기능을 MethodInterceptor 인터페이스를 통해 만듦 - InvocationHandler와 유사 - InvocationHandler는 타깃 오브젝트에 대한 정보를 제공 X - MethodInterceptor의 경우 ProxyFactoryBean으로 부터 타깃 오브젝트 정보까지 다 받음 - ProxyFactoryBean의 경우 인터페이스 자동검출 기능을 통해 타깃 오브젝트가 구현하는 인터페이스 정보 알아냄 - ProxyFactoryBean은 작은 단위의 템플릿/콜백 구조를 응용하여 작성되었기에 MethodInterceptor을 싱글톤으로 공유 가능 - MethodInterceptor는 타깃 오브젝트의 메서드를 실행할 수 있는 기능있기에, MethodInterceptor는 "부가 기능 제공에만 집중 가능" - MethodInterceptor... 콜백 오브젝트 - proceed() 메서드를 통해 타깃 오브젝트의 메서드를 내부적으로 실행 - 일종의 공유 가능한 템플릿으로 동작 - MethodInterceptor 재사용 가능한 순수한 부가 기능 코드만 남겨둠 (이를 어드바이스라 지칭) - 어드바이스 & 포인트컷 - 어드바이스: 부가기능을 제공하는 오브젝트 - 포인트컷: 메서드 선정 알고리즘 - 프록시 처리 순서 - 클라이언트의 요청 - 포인트 컷에게 부가 기능을 부여할 메서드인지 확인 부탁 - 부여할 대상이라면 MethodInterceptor 호출 - 어드바이스가 부가기능을 부여하는 중에 타깃 메서드의 호출이 필요하다면, MethodInvocation 타입 콜백 오브젝트의 proceed() 메서드 호출