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
- Thymeleaf
- jpa
- http
- 스프링 핵심 원리
- 김영한
- Greedy
- transaction
- 스프링 핵심 기능
- AOP
- QueryDSL
- 인프런
- JPQL
- pointcut
- springdatajpa
- Spring Boot
- Proxy
- SpringBoot
- 그리디
- Exception
- kotlin
- db
- 알고리즘
- Android
- spring
- 백준
- 스프링
- Servlet
- java
- 자바
- JDBC
Archives
- Today
- Total
개발자되기 프로젝트
[프록시 팩토리] 프록시 팩토리 - 예제1 본문
1. Advice
- Advice 는 프록시에 적용하는 부가 기능 로직이다.
- 이것은 JDK 동적 프록시가 제공하는 InvocationHandler 와 CGLIB가 제공하는 MethodInterceptor 의 개념과 유사.
- 둘을 개념적으로 추상화 한 것이다.
- 프록시 팩토리를 사용하면 둘 대신에 Advice 를 사용하면 된다.
- Advice 를 만드는 방법은 여러가지가 있지만, 기본적인 방법은 다음 인터페이스를 구현하면 된다.
- Methodinterceptor - 스프링이 제공하는 코드 -> Advice는??? : Interceptor가 Advice를 상속함 ㅋㅋㅋ
package org.aopalliance.intercept;
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation invocation) throws Throwable;
}
- MethodInvocation invocation
- 내부에는 다음 메서드를 호출하는 방법, 현재 프록시 객체 인스턴스, args , 메서드 정보 등이
포함되어 있다. - 기존에 파라미터로 제공되는 부분들이 이 안으로 모두 들어갔다고 생각하면 된다.
- 내부에는 다음 메서드를 호출하는 방법, 현재 프록시 객체 인스턴스, args , 메서드 정보 등이
- CGLIB의 MethodInterceptor 와 이름이 같으므로 패키지 이름에 주의하자
- 참고로 여기서 사용하는 org.aopalliance.intercept 패키지는 스프링 AOP 모듈( spring-top )
안에 들어있다.
- 참고로 여기서 사용하는 org.aopalliance.intercept 패키지는 스프링 AOP 모듈( spring-top )
- MethodInterceptor 는 Interceptor 를 상속하고 Interceptor 는 Advice 인터페이스를 상속한다.
2. Advice 작성.
@Slf4j
public class TimeAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
log.info("TimeProxy 실행");
long startTime = System.currentTimeMillis();
Object result = invocation.proceed(); //target을 찾아서 target의 method 호출
long endTime = System.currentTimeMillis();
long resultTime = endTime - startTime;
log.info("TimeProxy 종료 resultTime = {}", resultTime);
return result;
}
}
- TimeAdvice 는 앞서 설명한 MethodInterceptor 인터페이스를 구현한다. 패키지 이름에 주의하자.
- Object result = invocation.proceed()
- invocation.proceed() 를 호출하면 target 클래스를 호출하고 그 결과를 받는다.
- 그런데 기존에 보았던 코드들과 다르게 target 클래스의 정보가 보이지 않는다.
- target 클래스의 정보는 MethodInvocation invocation 안에 모두 포함되어 있다.
- 그 이유는 프록시 팩토리로 프록시를 생성하는 단계에서 이미 target 정보를 파라미터로 전달받기 때문이다.
3. TEST
@Slf4j
public class ProxyFactoryTest {
@Test
@DisplayName("인터페이스가 있으면 JDK 동적 프록시 사용")
void interfaceProxy(){
ServiceInterface target = new ServiceImpl();
ProxyFactory proxyFactory = new ProxyFactory(target);
proxyFactory.addAdvice(new TimeAdvice());
ServiceInterface proxy = (ServiceInterface) proxyFactory.getProxy();
log.info("targetClass={}", target.getClass());
log.info("proxyClass={}", proxy.getClass());
proxy.save();
//프록시팩토리 쓸 때 만 사용 가능.
assertThat(AopUtils.isAopProxy(proxy)).isTrue();
assertThat(AopUtils.isJdkDynamicProxy(proxy)).isTrue();
assertThat(AopUtils.isCglibProxy(proxy)).isFalse();
}
}
23:41:10.094 [main] INFO hello.proxy.proxyfactory.ProxyFactoryTest - targetClass=class hello.proxy.common.service.ServiceImpl
23:41:10.103 [main] INFO hello.proxy.proxyfactory.ProxyFactoryTest - proxyClass=class com.sun.proxy.$Proxy10
23:41:10.112 [main] INFO hello.proxy.common.advice.TimeAdvice - TimeProxy 실행
23:41:10.112 [main] INFO hello.proxy.common.service.ServiceImpl - save 호출
23:41:10.112 [main] INFO hello.proxy.common.advice.TimeAdvice - TimeProxy 종료 resultTime = 0
- new ProxyFactory(target)
- 프록시 팩토리를 생성할 때, 생성자에 프록시의 호출 대상을 함께 넘겨준다.
- 프록시 팩토리는 이 인스턴스 정보를 기반으로 프록시를 만들어낸다.
- 만약 이 인스턴스에 인터페이스가 있다면 JDK 동적 프록시를 기본으로 사용하고
인터페이스가 없고 구체 클래스만 있다면 CGLIB를 통해서 동적 프록시를 생성한다. - 여기서는 target 이 new ServiceImpl() 의 인스턴스이기 때문에 ServiceInterface 인터페이스가 있다.
- 따라서 이 인터페이스를 기반으로 JDK 동적 프록시를 생성한다.
- proxyFactory.addAdvice(new TimeAdvice())
- 프록시 팩토리를 통해서 만든 프록시가 사용할 부가기능 로직을 설정한다.
- JDK 동적 프록시가 제공하는 InvocationHandler 와 CGLIB가 제공하는 MethodInterceptor 의 개념과 유사.
- 이렇게 프록시가 제공하는 부가 기능 로직을 어드바이스 ( Advice )라 한다.
- 번역하면 조언을 해준다고 생각하면 된다.
- proxyFactory.getProxy() : 프록시 객체를 생성하고 그 결과를 받는다.
4. Proxy 적용 확인
프록시 팩토리로 프록시가 잘 적용되었는지 확인하려면 다음 기능을 사용하면 된다.
- AopUtils.isAopProxy(proxy)
- 프록시 팩토리를 통해서 프록시가 생성되면 JDK 동적 프록시나, CGLIB 모두 참이다.
- AopUtils.isJdkDynamicProxy(proxy)
- 프록시 팩토리를 통해서 프록시가 생성되고, JDK 동적 프록시인 경우 참
- AopUtils.isCglibProxy(proxy)
- 프록시 팩토리를 통해서 프록시가 생성되고, CGLIB 동적 프록시인 경우 경우 참
- 물론 proxy.getClass() 처럼 인스턴스의 클래스 정보를 직접 출력해서 확인할 수 있다.
5. GitHub : 211230 Proxy Factory 1
'인프런 > [인프런] 스프링 핵심 원리 - 고급' 카테고리의 다른 글
Pointcut, Advice, Advisor - 소개 (0) | 2021.12.31 |
---|---|
[프록시팩토리] 프록시 팩토리-예제2, CGLIB (0) | 2021.12.31 |
[프록시 팩토리] 스프링이 지원하는 프록시 (0) | 2021.12.30 |
[동적 프록시] CGLIB - 구체클래스 기반 (0) | 2021.12.30 |
[동적프록시] JDK 동적프록시 - 적용2, 필터 (0) | 2021.12.30 |
Comments