본문 바로가기

Study

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

스프링에서 프록시를 적용할 떄 사용하는 3가지 개념

 

포인트컷 : 어떤 시점에 적용할 것인가에 대한 개념

Pointcut 인터페이스를 기반으로 동작하며 구현하려면 상속받아서 구현하면 된다.

ClassFilter와 MethodMatcher 두가지를 제공하는데

클래스조건, 메소드관련 조건을 걸 수 있다.

@Test
void advisorTest1() {
    ServiceInterface target = new ServiceInterfaceImpl();
    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();
}

static class MyPointcut implements Pointcut {
    @Override
    public ClassFilter getClassFilter() {
        return ClassFilter.TRUE;
    }

    @Override
    public MethodMatcher getMethodMatcher() {
        return new MyMethodMatcher();
    }
}

@Slf4j
static class MyMethodMatcher implements MethodMatcher {

    private String matchName = "save";

    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        boolean result = method.getName().equals(matchName);
        log.info("포인트컷 호출 method={}, targetClass={}", method.getName(), targetClass);
        log.info("포인트컷 결과 result={}", result);
        return result;
    }

    @Override
    public boolean isRuntime() {
        return false;
    }

    // isRuntime()가 true인 경우 파라미터가 동적이라고 봄 캐싱을 하지 않는다.
    @Override
    public boolean matches(Method method, Class<?> targetClass, Object... args) {
        return false;
    }
}

 

advice는 프록시가 동작시에 수행하는 내용

MethodInterceptor를 가보면 Interceptor를 상속받고 Advice를 상속받는 것을 확인할 수 있다.

 

advisor는 포인트컷1 + advice1이다.

 

최종적으로는 어드바이저를 한번에 사용한다.

 

스프링에서는 실제적으로 타켓 객체에 대해서 프록시는 1만 생성하고 어드바이저를 여러개 만들어서 동작한다.

@Test
@DisplayName("하나의 프록시, 여러 어드바이저")
void multiAdvisorTest2() {
    // client -> proxy1 -> advisor2 -> advisor1 -> target
    DefaultPointcutAdvisor advisor1 = new DefaultPointcutAdvisor(Pointcut.TRUE, new Advice1());
    DefaultPointcutAdvisor advisor2 = new DefaultPointcutAdvisor(Pointcut.TRUE, new Advice2());

    // 프로시1 생성
    ServiceInterface target = new ServiceInterfaceImpl();
    ProxyFactory proxyFactory1 = new ProxyFactory(target);

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

    proxy1.save();
}

@Slf4j
static class Advice1 implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        log.info("advice1 호출");
        return invocation.proceed();
    }
}

@Slf4j
static class Advice2 implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        log.info("advice2 호출");
        return invocation.proceed();
    }
}

'Study' 카테고리의 다른 글

Proxy Factory  (0) 2022.10.05
Cglib dynamic proxy  (0) 2022.10.05
JDK Dynamic Proxy  (0) 2022.09.30
인터페이스 기반 vs 구체 클래스 기반 프록시  (0) 2022.09.29
프록시 패턴 & 데코레이터 패턴  (0) 2022.09.22