개발놀이터

포인트컷, 어드바이스, 어드바이저 본문

Spring/Spring

포인트컷, 어드바이스, 어드바이저

마늘냄새폴폴 2022. 1. 19. 17:28

이 포스팅은 인프런 김영한 님의 스프링 핵심 원리 고급 편을 보고 각색한 포스팅입니다. 자세한 내용은 강의를 확인해주세요

 

 

포인트컷 : 어디에 부가 기능을 적용할지, 어디에 부가 기능을 적용하지 않을지 판단하는 필터링 로직이다. 주로 클래스와 메서드 이름으로 필터링한다. 이름 그대로 어떤 포인트에 기능을 적용할지 하지 않을지 잘라서 구분하는 것이다.

 

어드바이스 : 이전 포스팅에서 본 것 처럼 프록시가 호출하는 부가 기능이다. 단순하게 프록시 로직이라 생각하면 된다.

 

어드바이저 : 단순하게 하나의 포인트컷과 하나의 어드바이스를 가지고 있는 것이다. 쉽게 이야기해서 포인트컷1 + 어드바이스1이다.

 

 

정리하면 부가 기능 로직을 적용해야 하는데, 포인트컷으로 어디에 적용할지를 선택하고, 어드바이스로 어떤 로직을 적용할지 선택하는 것이다. 그리고 어디에 어떤 로직을 모두 알고 있는 것이 어드바이저이다.

 

이렇게 구분한 것은 역할과 책임을 명확하게 분리한 것이다.

 

포인트컷은 대상 여부를 확인하는 필터 역할만 담당하고 어드바이스는 깔끔하게 부가 기능 로직만 담당한다.

    @Test
    void advisorTest1() {
        ServiceInterface target = new ServiceImpl();
        ProxyFactory proxyFactory = new ProxyFactory(target);
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(Pointcut.TRUE, new TimeAdvice());
        proxyFactory.addAdvisor(advisor);
        ServiceInterface proxy = (ServiceInterface) proxyFactory.getProxy();

        proxy.save();
        proxy.find();
    }

코드설명

-new DefaultPoincutAdvisor : Advisor 인터페이스의 가장 일반적인 구현체이다. 생성자를 통해 하나의 포인트컷과 하나의 어드바이스를 넣어주면 된다. 어드바이저는 하나의 포인트컷과 하나의 어드바이스로 구성된다.

 

-Pointcut.TRUE : 항상 true를 반환하는 포인트컷이다. 이후에 직접 포인트컷을 구현해볼 것이다.

 

-new TimeAdvice() : 앞선 포스팅에서 개발한 TimeAdvice 어드바이스를 제공한다.

 

-proxyFactory.addAdvisor(advisor) : 프록시 팩토리에 적용할 어드바이저를 지정한다. 어드바이저는 내부에 포인트컷과 어드바이스를 모두 가지고 있다. 따라서 어디에 어떤 부가 기능을 적용해야 할지 어드바이스 하나로 알 수 있다. 프록시  팩토리를 사용할 때 어드바이저는 필수이다.

 

 

이제 스프링에서 제공하는 포인트컷을 사용해보자

    @Test
    @DisplayName("스프링이 제공하는 포인트 컷")
    void advisorTest3() {
        ServiceInterface target = new ServiceImpl();
        ProxyFactory proxyFactory = new ProxyFactory(target);
        NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
        pointcut.setMappedName("save");
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, new TimeAdvice());
        proxyFactory.addAdvisor(advisor);
        ServiceInterface proxy = (ServiceInterface) proxyFactory.getProxy();

        proxy.save();
        proxy.find();
    }

NameMatchMethodPointcut을 선언하고 setMappedName으로 메서드 이름을 지정하면 포인트컷이 완성된다.

 

 

스프링은 무수히 많은 포인트컷을 제공하는데 대표적인 몇가지만 알아보자

-NameMatchMethodPoincut : 메서드 이름을 기반으로 매칭한다. 내부에서는 PatternMatchUtils를 사용한다.

-JdkRegexpMethodPointcut : JDK 정규 표현식을 기반으로 포인트컷을 매칭한다.

-TruePointcut : 항상 참을 반환한다.

-AnnotationMatchingPointcut : 어노테이션 기반으로 맻이한다.

-AspectJExpressionPointcut : aspectJ 표현식으로 매칭한다.

 

이 중 가장 중요한것은 AspectJExpressionPointcut이다. 실무에서는 사용하기도 편리하고 기능도 가장 많기 때문이다. aspectJ 표현식과 사용방법은 중요해서 이후 AOP를 포스팅할때 다시 자세히 설명하겠다. 

 

 

여러 어드바이저를 함께 적용

어드바이저는 하나의 포인트컷과 하나의 어드바이스를 가지고 있다. 만약 여러 어드바이저를 하나의 target에 적용하려면 어떻게 해야 할까? 쉽게 이야기해ㅑ서 하나의 target에 여러 어드바이스를 적용하려면 어떻게 해야할까?

 

    @Test
    @DisplayName("하나의 프록시, 여러 어드바이저")
    void multiAdvisorTest2() {
        //client -> proxy -> advisor2 -> advisor1 -> target

        DefaultPointcutAdvisor advisor1 = new DefaultPointcutAdvisor(Pointcut.TRUE, new Advice1());
        DefaultPointcutAdvisor advisor2 = new DefaultPointcutAdvisor(Pointcut.TRUE, new Advice2());

        //프록시 1 생성
        ServiceInterface target = new ServiceImpl();
        ProxyFactory proxyFactory1 = new ProxyFactory(target);

        proxyFactory1.addAdvisor(advisor2);
        proxyFactory1.addAdvisor(advisor1);
        ServiceInterface proxy1 = (ServiceInterface) proxyFactory1.getProxy();

        proxy1.save();
    }

프록시팩토리에서 제공하는 addAdvisor를 사용하면 된다. 

 

이 코드를 그림으로 설명하면 다음과 같다.

 

'Spring > Spring' 카테고리의 다른 글

@Aspect  (0) 2022.01.20
빈 후처리기  (0) 2022.01.20
프록시 팩토리  (0) 2022.01.19
동적 프록시  (0) 2022.01.18
디자인패턴 (프록시 패턴, 데코레이터 패턴)  (0) 2022.01.17