티스토리 뷰

Spring

[Spring] 포인트컷(Pointcut)

hyuuny 2022. 5. 19. 22:40

포인트컷

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

public interface Pointcut {
      ClassFilter getClassFilter();
      MethodMatcher getMethodMatcher();
}

 public interface ClassFilter {
      boolean matches(Class<?> clazz);
}

public interface MethodMatcher {
      boolean matches(Method method, Class<?> targetClass);
      //..
}

포인트컷은 크게 ClassFilterMethodMatcher 둘로 이루어진다.
ClassFilter는 클래스가 맞는지, MethodMatcher는 메서드가 맞는지 확인할 때 사용하며, 둘다 true로 반환해야 어드바이스를 적용할 수 있다.


포인트컷은 대상 여부를 확인하는 필터 역할만 수행하고, 어드바이스는 부가 기능 로직만 수행함으로써, 역할과 책임이 명확하게 분리된 것을 확인할 수 있다. 스프링의 어드바이저는 하나의 포인트컷과 하나의 어드바이스로 구성된다.



포인트컷(Pointcut) 만들어보기

포인트컷을 이용해서 save() 메서드에는 어드바이스 로직을 적용하지만, find() 메서드에는 어드바이스 로직을 적용하지 않도록 해보자.


MyPointcut.class

static class MyPointcut implements Pointcut {

    @Override
    public ClassFilter getClassFilter() {
      return ClassFilter.TRUE;
    }

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

Pointcut 인터페이스를 직접 구현한 MyPointcut이다.
클래스 필터는 항상 true를 반환하도록 했고, 메서드 비교 기능은 MyMethodMatcher를 사용한다.


MyMethodMatcher.class

  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;
    }

    @Override
    public boolean matches(Method method, Class<?> targetClass, Object... args) {
      return false;
    }
  }

MethodMatcher 인터페이스를 직접 구현한 MethodMatcher이다.

matches()에는 method, targetClass 정보가 넘어오는데, 이 정보로 어드바이스를 적용할지 적용하지 않을지 판단할 수 있다.

save라는 이름을 가진 메서드만 어드바이스가 적용되도록 설정하였다. MyPointcut을 이용한다면, save 이외에는 어드바이스가 적용되지 않아야 할 것이다.


Test code

  @DisplayName("직접 만든 포인트컷")
  @Test
  void madePointcut() {
    ServiceInterface target = new ServiceImpl();
    ProxyFactory proxyFactory = new ProxyFactory(target);
    DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(new MyPointcut(), new TimeAdvice());
    proxyFactory.addAdvisor(advisor);
    ServiceInterface proxy = (ServiceInterface) proxyFactory.getProxy();

    proxy.save(); // 어드바이스가 적용된다.
    proxy.find(); // 어드바이스가 적용되지 않는다.
  }

결과

실행된 결과를 보면, 기대한 것과 같이 save()를 호출할 때는 어드바이스가 적용됐지만, find()를 호출할 때는 어드바이스가 적용되지 않은 모습을 확인할 수 있다.



Reference

김영한. 스프링 핵심 원리 - 고급편. 인프런.
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B3%A0%EA%B8%89%ED%8E%B8#

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함