Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
Tags
- 스프링
- Servlet
- 자바
- AOP
- Spring Boot
- springdatajpa
- QueryDSL
- 백준
- SpringBoot
- java
- 김영한
- Exception
- 스프링 핵심 기능
- 그리디
- Proxy
- 스프링 핵심 원리
- pointcut
- JDBC
- db
- JPQL
- kotlin
- 인프런
- http
- 알고리즘
- transaction
- Greedy
- Thymeleaf
- jpa
- spring
- Android
Archives
- Today
- Total
개발자되기 프로젝트
Advisor - 예제, PointCut 만들기 본문
save() 메서드에는 어드바이스 로직을 적용하지만, find() 메서드에는 어드바이스 로직을 적용하지 말자.
이런 기능에 특화되어서 제공되는 것이 바로 포인트컷이다.
1. Pointcut관련 인터페이스 - 스프링
public interface Pointcut {
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
}
public interface ClassFilter {
boolean matches(Class<?> clazz);
}
public interface MethodMatcher {
boolean matches(Method method, Class<?> targetClass);
//..
}
- 포인트컷은 크게 ClassFilter 와 MethodMatcher 둘로 이루어진다.
- 이름 그대로 하나는 클래스가 맞는지, 하나는 메서드가 맞는지 확인할 때 사용한다.
- 둘다 true 로 반환해야 어드바이스를 적용할 수 있다.
- 일반적으로 스프링이 이미 만들어둔 구현체를 사용하지만 개념 학습 차원에서 간단히 직접 구현해보자.
2. MyPointCut, Test
@Test
@DisplayName("직접 만든 포인트컷")
void advisorTest2(){
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();
}
static class MyPointcut implements Pointcut{
@Override
public ClassFilter getClassFilter() {
return ClassFilter.TRUE; //항상 true를 반환하는 class filter
}
@Override
public MethodMatcher getMethodMatcher() {
return new MyMethodMatcher();
}
}
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;
}
}
- MyPointcut
- 직접 구현한 포인트컷이다. Pointcut 인터페이스를 구현한다.
- 현재 메서드 기준으로 로직을 적용하면 된다.
- 클래스 필터는 항상 true 를 반환하도록 했고, 메서드 비교기능은 MyMethodMatcher 를 사용한다.
- MyMethodMatcher
- 직접 구현한 MethodMatcher 이다.
- MethodMatcher 인터페이스를 구현한다.
- matches() : 이 메서드에 method , targetClass 정보가 넘어온다.
- 이 정보로 어드바이스를 적용할지 적용하지 않을지 판단할 수 있다.
- 여기서는 메서드 이름이 "save" 인 경우에 true 를 반환하도록 판단 로직을 적용했다.
- isRuntime() , matches(... args)
- isRuntime() 이 값이 참이면 matches(... args) 메서드가 대신 호출된다.
- 동적으로 넘어오는 매개변수를 판단 로직으로 사용할 수 있다.
- isRuntime() 이 false 인 경우 클래스의 정적 정보만 사용하기 때문에
- 스프링이 내부에서 캐싱을 통해 성능 향상이 가능하지만,
- isRuntime() 이 true 인 경우 매개변수가 동적으로 변경된다고 가정하기 때문에 캐싱을 하지 않는다.
- 크게 중요한 부분은 아니니 참고만 하고 넘어가자
- new DefaultPointcutAdvisor(new MyPointcut(), new TimeAdvice())
어드바이저에 직접 구현한 포인트컷을 사용한다.
3. 결과
포인트컷 호출 method=save, targetClass=class hello.proxy.common.service.ServiceImpl
포인트컷 결과 result = true
TimeAdvice - TimeProxy 실행
ServiceImpl - save 호출
TimeAdvice - TimeProxy 종료 resultTime = 0
포인트컷 호출 method=find, targetClass=class hello.proxy.common.service.ServiceImpl
포인트컷 결과 result = false
ServiceImpl - find 호출
- 의도한 바와 같이 save()의 경우에만 Advice가 적용되었다.
- save()호출하는 경우
- 클라이언트가 프록시의 save() 를 호출한다.
- 포인트컷에 Service 클래스의 save() 메서드에 어드바이스를 적용해도 될지 물어본다.
- 포인트컷이 true 를 반환한다. 따라서 어드바이스를 호출해서 부가 기능을 적용한다.
- 이후 실제 인스턴스의 save() 를 호출한다.
- find() 호출하는 경우
- 클라이언트가 프록시의 find() 를 호출한다.
- 포인트컷에 Service 클래스의 find() 메서드에 어드바이스를 적용해도 될지 물어본다.
- 포인트컷이 false 를 반환한다. 따라서 어드바이스를 호출하지 않고, 부가 기능도 적용되지 않는다.
- 실제 인스턴스를 호출한다.
4. GitHub : 211231 Poincut, Advice, Advisor 2
'인프런 > [인프런] 스프링 핵심 원리 - 고급' 카테고리의 다른 글
여러 개의 Advisor 적용 (0) | 2022.01.01 |
---|---|
Pointcut - 스프링이 제공하는 pointcut (0) | 2021.12.31 |
Advisor - 예제 (0) | 2021.12.31 |
Pointcut, Advice, Advisor - 소개 (0) | 2021.12.31 |
[프록시팩토리] 프록시 팩토리-예제2, CGLIB (0) | 2021.12.31 |
Comments