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
- http
- transaction
- 스프링 핵심 원리
- spring
- 백준
- SpringBoot
- 스프링
- db
- Android
- QueryDSL
- Servlet
- JPQL
- AOP
- Proxy
- 김영한
- 그리디
- springdatajpa
- JDBC
- 알고리즘
- jpa
- Thymeleaf
- 자바
- java
- 인프런
- Exception
- pointcut
- 스프링 핵심 기능
- kotlin
- Spring Boot
- Greedy
Archives
- Today
- Total
개발자되기 프로젝트
[프록시팩토리] 프록시 팩토리-예제2, CGLIB 본문
1. 구체 클래스만 있는 경우
@Test
@DisplayName("구체클래스만 있으면 CGLIB 사용")
void concreteProxy(){
ConcreteService target = new ConcreteService();
ProxyFactory proxyFactory = new ProxyFactory(target);
proxyFactory.addAdvice(new TimeAdvice());
ConcreteService proxy = (ConcreteService) proxyFactory.getProxy();
log.info("targetClass={}", target.getClass());
log.info("proxyClass={}", proxy.getClass());
proxy.call();
//프록시팩토리 쓸 때 만 사용 가능.
assertThat(AopUtils.isAopProxy(proxy)).isTrue();
assertThat(AopUtils.isJdkDynamicProxy(proxy)).isFalse();
assertThat(AopUtils.isCglibProxy(proxy)).isTrue();
}
INFO hello.proxy.proxyfactory.ProxyFactoryTest - targetClass=class hello.proxy.common.service.ConcreteService
INFO hello.proxy.proxyfactory.ProxyFactoryTest - proxyClass=class hello.proxy.common.service.ConcreteService$$EnhancerBySpringCGLIB$$e01fc80b
INFO hello.proxy.common.advice.TimeAdvice - TimeProxy 실행
INFO hello.proxy.common.service.ConcreteService - ConcreteService call 호출
INFO hello.proxy.common.advice.TimeAdvice - TimeProxy 종료 resultTime = 17
- ...$$EnhancerBySpringCGLIB$$e01fc80b : 기대한 대로 CGLIB을 사용했다.
2. ProxyTargetClass 사용
- 인터페이스가 있어도 CGLIB를 사용하고 싶은 경우
- setProxyTargetClass(true)
@Test
@DisplayName("ProxyTargetClass 옵션을 사용하면 인터페이스가 있어도 CGLIB 사용, 클래스 기반 프록시 사용")
void proxyTargetClass(){
ServiceInterface target = new ServiceImpl();
ProxyFactory proxyFactory = new ProxyFactory(target);
proxyFactory.setProxyTargetClass(true); //true : 항상 CGLIB
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)).isFalse();
assertThat(AopUtils.isCglibProxy(proxy)).isTrue();
}
INFO hello.proxy.proxyfactory.ProxyFactoryTest - targetClass=class hello.proxy.common.service.ServiceImpl
INFO hello.proxy.proxyfactory.ProxyFactoryTest - proxyClass=class hello.proxy.common.service.ServiceImpl$$EnhancerBySpringCGLIB$$e730a17b
INFO hello.proxy.common.advice.TimeAdvice - TimeProxy 실행
INFO hello.proxy.common.service.ServiceImpl - save 호출
INFO hello.proxy.common.advice.TimeAdvice - TimeProxy 종료 resultTime = 16
- ...ServiceImpl$$EnhancerBySpringCGLIB$$e730a17b : 인터페이스가 있지만 CGLIB를 사용했다.
- 따라서 ServiceImpl 클래스를 상속받아 클래스 기반의 프록시를 만들었다.
3. 프록시 팩토리의 기술 선택 방법
- 대상에 인터페이스가 있으면: JDK 동적 프록시, 인터페이스 기반 프록시
- 대상에 인터페이스가 없으면: CGLIB, 구체 클래스 기반 프록시
- proxyTargetClass=true : CGLIB, 구체 클래스 기반 프록시, 인터페이스 여부와 상관없음
4. 정리
- 프록시 팩토리의 서비스 추상화 덕분에 구체적인 CGLIB, JDK 동적 프록시 기술에 의존하지 않고,
- 매우 편리하게 동적 프록시를 생성할 수 있다.
- 프록시의 부가 기능 로직도 특정 기술에 종속적이지 않게 Advice 하나로 편리하게 사용할 수 있었다.
- 이것은 프록시 팩토리가 내부에서 JDK 동적 프록시인 경우 InvocationHandler 가 Advice 를 호출하도록 개발해두고, CGLIB인 경우 MethodInterceptor 가 Advice 를 호출하도록 기능을 개발해두었기 때문이다.
* 참고
- 스프링 부트는 AOP를 적용할 때 기본적으로 proxyTargetClass=true 로 설정해서 사용한다.
- 따라서 인터페이스가 있어도 항상 CGLIB를 사용해서 구체 클래스를 기반으로 프록시를 생성한다.
5. GitHub : 211231 Proxy Factory 2
'인프런 > [인프런] 스프링 핵심 원리 - 고급' 카테고리의 다른 글
Advisor - 예제 (0) | 2021.12.31 |
---|---|
Pointcut, Advice, Advisor - 소개 (0) | 2021.12.31 |
[프록시 팩토리] 프록시 팩토리 - 예제1 (0) | 2021.12.30 |
[프록시 팩토리] 스프링이 지원하는 프록시 (0) | 2021.12.30 |
[동적 프록시] CGLIB - 구체클래스 기반 (0) | 2021.12.30 |
Comments