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
- Proxy
- 스프링 핵심 원리
- 스프링
- java
- 알고리즘
- 인프런
- db
- 스프링 핵심 기능
- jpa
- Greedy
- 김영한
- Spring Boot
- QueryDSL
- AOP
- 그리디
- transaction
- Thymeleaf
- spring
- kotlin
- http
- Exception
- 자바
- Android
- Servlet
- JDBC
- SpringBoot
- 백준
- pointcut
- springdatajpa
- JPQL
Archives
- Today
- Total
개발자되기 프로젝트
Interface기반 Proxy - 적용 본문
인터페이스와 구현체가 있는 V1 App에 지금까지 학습한 프록시를 도입하여 LogTrace를 사용하자.
- 프록시를 사용하면 기존 코드를 전혀 수정하지 않고 로그 추적 기능을 도입할 수 있다.
1. V1 기본 클래스 의존 관계, 런타임 의존관계
2. 로그 추적용 프록시 추가
애플리케이션 실행 시점에 프록시를 사용하도록 의존관계를 설정해 주면 됨. (설정 파일을 활용)
3. 프록시 적용
- OrderRepositoryProxy
import hello.proxy.app.v1.OrderRepositoryV1;
import hello.proxy.trace.TraceStatus;
import hello.proxy.trace.logtrace.LogTrace;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class OrderRepositoryInterfaceProxy implements OrderRepositoryV1 {
private final OrderRepositoryV1 target;
private final LogTrace logTrace;
@Override
public void save(String itemId) {
TraceStatus status = null;
try {
status = logTrace.begin("OrderRepository.request()");
//target 호출
target.save(itemId);
logTrace.end(status);
}catch (Exception e){
logTrace.exception(status, e);
throw e;
}
}
- OrderServiceProxy
import hello.proxy.app.v1.OrderServiceV1;
import hello.proxy.trace.TraceStatus;
import hello.proxy.trace.logtrace.LogTrace;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class OrderServiceInterfaceProxy implements OrderServiceV1 {
private final OrderServiceV1 target;
private final LogTrace logTrace;
@Override
public void orderItem(String itemId) {
TraceStatus status = null;
try {
status = logTrace.begin("OrderServiceV1.orderItem()");
//target 호출
target.orderItem(itemId);
logTrace.end(status);
}catch (Exception e){
logTrace.exception(status, e);
throw e;
}
}
}
- OrderController Proxy
import hello.proxy.app.v1.OrderControllerV1;
import hello.proxy.trace.TraceStatus;
import hello.proxy.trace.logtrace.LogTrace;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class OrderControllerInterfaceProxy implements OrderControllerV1 {
private final OrderControllerV1 target;
private final LogTrace logTrace;
@Override
public String request(String itemId) {
TraceStatus status = null;
try {
status = logTrace.begin("OrderController.request()");
//target 호출
String result = target.request(itemId);
logTrace.end(status);
return result;
}catch (Exception e){
logTrace.exception(status, e);
throw e;
}
}
@Override
public String noLog() {
return target.noLog();
}
}
4. Configuration
- Proxy를 사용하지 않은 Configuration은 구현체를 반환했다.
- Proxy를 적용하기 위해 구현체가 아닌 Proxy를 반환.
import hello.proxy.app.v1.*;
import hello.proxy.config.v1_proxy.interface_proxy.OrderControllerInterfaceProxy;
import hello.proxy.config.v1_proxy.interface_proxy.OrderRepositoryInterfaceProxy;
import hello.proxy.config.v1_proxy.interface_proxy.OrderServiceInterfaceProxy;
import hello.proxy.trace.logtrace.LogTrace;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class InterfaceProxyConfig {
//proxy를 반환. 스프링 빈에 프록시가 등록됨.
@Bean
public OrderControllerV1 orderController(LogTrace logTrace){
OrderControllerV1Impl controllerImpl = new OrderControllerV1Impl(orderService(logTrace));
return new OrderControllerInterfaceProxy(controllerImpl, logTrace);
}
@Bean
public OrderServiceV1 orderService(LogTrace logTrace){
OrderServiceV1Impl serviceImpl = new OrderServiceV1Impl(orderRepository(logTrace));
return new OrderServiceInterfaceProxy(serviceImpl, logTrace);
}
@Bean
public OrderRepositoryV1 orderRepository(LogTrace logTrace){
OrderRepositoryV1Impl repositoryImpl = new OrderRepositoryV1Impl();
return new OrderRepositoryInterfaceProxy(repositoryImpl, logTrace);
}
}
5. V1 Proxy 런타임 객체 의존관계 설정.
- 이제 프록시의 런타임 객체 의존 관계를 설정하면 된다.
- 기존에는 스프링 빈이 orderControlerV1Impl , orderServiceV1Impl 같은 실제 객체를 반환했다.
- 하지만 이제는 프록시를 사용해야한다.
- 따라서 프록시를 생성하고 프록시를 실제 스프링 빈 대신 등록한다.
- 실제 객체는 스프링 빈으로 등록하지 않는다.
- 프록시는 내부에 실제 객체를 참조하고 있다.
- 예를 들어서 OrderServiceInterfaceProxy 는 내부에 실제 대상 객체인 OrderServiceV1Impl 을 가지고 있다.
- 정리하면 다음과 같은 의존 관계를 가지고 있다.
- proxy -> target
- orderServiceInterfaceProxy -> orderServiceV1Impl
- 스프링 빈으로 실제 객체 대신에 프록시 객체를 등록했기 때문에
- 앞으로 스프링 빈을 주입 받으면 실제 객체 대신에 프록시 객체가 주입된다.
- 실제 객체가 스프링 빈으로 등록되지 않는다고 해서 사라지는 것은 아니다.
- 프록시 객체가 실제 객체를 참조하기 때문에 프록시를 통해서 실제 객체를 호출할 수 있다.
- 쉽게 이야기해서 프록시 객체 안에 실제 객체가 있는 것이다.
- InterfaceProxyConfig 를 통해 프록시를 적용한 후 스프링 컨테이너에 프록시 객체가 등록된다.
- 스프링 컨테이너는 이제 실제 객체가 아니라 프록시 객체를 스프링 빈으로 관리한다.
- 이제 실제 객체는 스프링 컨테이너와는 상관이 없다. 실
- 제 객체는 프록시 객체를 통해서 참조될 뿐이다.
- 프록시 객체는 스프링 컨테이너가 관리하고 자바 힙 메모리에도 올라간다.
- 반면에 실제 객체는 자바 힙 메모리에는 올라가지만 스프링 컨테이너가 관리하지는 않는다.
6. 실행, LogTrace Bean 등록
//@Import({AppV1Config.class, AppV2Config.class})
@Import(InterfaceProxyConfig.class)
@SpringBootApplication(scanBasePackages = "hello.proxy.app") //주의
public class ProxyApplication {
public static void main(String[] args) {
SpringApplication.run(ProxyApplication.class, args);
}
@Bean
public LogTrace logTrace(){
return new ThreadLocalLogTrace();
}
}
[85033b82] OrderController.request()
[85033b82] |-->OrderServiceV1.orderItem()
[85033b82] | |-->OrderRepository.request()
[85033b82] | |<--OrderRepository.request() time=1014ms
[85033b82] |<--OrderServiceV1.orderItem() time=1015ms
[85033b82] OrderController.request() time=1020ms
7. GitHub : 211229 Interface 기반 Proxy 적용
'인프런 > [인프런] 스프링 핵심 원리 - 고급' 카테고리의 다른 글
구체 클래스 기반 프록시 - 적용 (0) | 2021.12.30 |
---|---|
구체 클래스 기반 프록시 - 예제 (0) | 2021.12.29 |
Proxy Pattern & Decorator Pattern (0) | 2021.12.28 |
Decorator Pattern 3 - chain (0) | 2021.12.28 |
Decorator Pattern 3 - chain (0) | 2021.12.28 |
Comments