오봉이와 함께하는 개발 블로그
스프링 핵심 원리 - 고급편 > 템플릿 콜백 패턴 (적용, 정의 및 정리) 본문
728x90
템플릿 콜백 패턴 - 적용
- TraceCallback 인터페이스
public interface TraceCallback<T> {
T call();
}
- TraceTemplate.java
public class TraceTemplate {
private final LogTrace trace;
public TraceTemplate(LogTrace trace) {
this.trace = trace;
}
public <T> T execute(String message, TraceCallback<T> callback) {
TraceStatus status = null;
try {
status = trace.begin(message);
T result = callback.call();
trace.end(status);
return result;
} catch (Exception e) {
trace.exception(status, e);
throw e;
}
}
}
TraceTemplate
은 템플릿 역할을 한다.execute(..)
를 보면message
데이터와 콜백인TraceCallback callback
을 전달 받는다.<T>
제네릭을 사용했다. 반환 타입을 정의한다.
V5
- OrderControllerV5
@RestController
public class OrderControllerV5 {
private final OrderServiceV5 orderService;
private final TraceTemplate template;
public OrderControllerV5(OrderServiceV5 orderService, LogTrace trace) {
this.orderService = orderService;
this.template = new TraceTemplate(trace);
}
@GetMapping("/v5/request")
public String request(@RequestParam("itemId") String itemId) {
return template.execute("OrderController.request()", new TraceCallback<>() {
@Override
public String call() {
orderService.orderItem(itemId);
return "ok";
}
});
}
}
this.template = new TraceTemplate(trace)
:trace
의존관계 주입을 받으면서 필요한TraceTemplate
템플릿을 생성한다.TraceTemplate
을 처음부터 스프링 빈으로 등록하고 주입받아도 된다. (선택사항)- 스프링 빈 생성 시 new TraceTemplate()를 하기 때문에 TraceTemplate는 빈 생성 시 최초 한 번만 생성된다.
- 위 방식의 장점은 테스트 시 LogTrace만 빈으로 생성하고 TrateTemplate은 빈으로 등록하지 않아도 자동으로 생성되기 때문에 의존성 주입이 보다 간단하다
- @MockBean LogTrace logTrace
- @MockBean TraceTemplate template
- 매 Request마다 new TraceTemplate()을 통해 생성할 수도 있지만, 그렇게 되면 매 요청 시 생성하기 때문에 오버헤드 발생
- OrderServiceV5
@Service
public class OrderServiceV5 {
private final OrderRepositoryV5 orderRepository;
private final TraceTemplate template;
public OrderServiceV5(OrderRepositoryV5 orderRepository, LogTrace trace) {
this.orderRepository = orderRepository;
this.template = new TraceTemplate(trace);
}
public void orderItem(String itemId) {
template.execute("OrderService.orderItem()", () -> {
orderRepository.save(itemId);
return null;
});
}
}
template.execute(.., new TraceCallback(){..})
: 템플릿을 실행하면서 콜백을 전달한다. 여기는 콜백으로 람다를 전달- OrderRepositoryV5
@Repository
public class OrderRepositoryV5 {
private final TraceTemplate template;
public OrderRepositoryV5(LogTrace trace) {
this.template = new TraceTemplate(trace);
}
public void save(String itemId) {
template.execute("OrderRepository.save()", () -> {
//저장 로직
if (itemId.equals("ex")) {
throw new IllegalStateException("예외 발생!"); }
sleep(1000);
return null;
});
}
private void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (Exception e) {
e.printStackTrace();
}
}
}
로그
[aaaaaaaa] OrderController.request()
[aaaaaaaa] |-->OrderService.orderItem()
[aaaaaaaa] | |-->OrderRepository.save()
[aaaaaaaa] | |<--OrderRepository.save() time=1001ms
[aaaaaaaa] |<--OrderService.orderItem() time=1003ms
[aaaaaaaa] OrderController.request() time=1004ms
정리
템플릿 메서드 -> 전략 -> 템플릿 콜백 패턴까지 사용하면서 변하는 코드와 변하지 않는 코드를 분리하고, 더 적은 코드로 로그 추적기를 사용하기 위해 이런 저런 코드를 보았다.
그러나 지금까지의 방식으로는 로그 추적기 적용을 위해서는 모든 엔드포인트, 서비스, 리포지토리의 원본 코드를 수정해야 하는 문제가 있다.
클래스가 XXX개라면, 그 안에 메서드가 각 3개씩만 있어도 XXX*3개 모두 작업해야 한다.
템플릿 콜백 패턴까지 적용하면서 그나마 조금이라도 덜 힘들겠지만, 말 그대로 덜 힘든 것이다.
개발자는 게으른 개발자가 성공한다. 자동화와 딸깍이 습관화 되어야 한다..
다음엔 원본 코드를 수정하지 않고 로그 추적기 적용 방법을 알아보자.
출처: 김영한 지식공유자님의 스프링 핵심 원리 고급편
728x90
'BE > Spring' 카테고리의 다른 글
스프링 핵심 원리 - 고급편 > 데코레이터 (0) | 2024.08.25 |
---|---|
스프링 핵심 원리 - 고급편 > 프록시 (0) | 2024.08.22 |
스프링 핵심 원리 - 고급편 > 템플릿 콜백 패턴 (시작, 예제) (0) | 2024.05.10 |
스프링 핵심 원리 - 고급편 > 전략 패턴 (예제 2, 예제 3) (0) | 2024.05.10 |
스프링 핵심 원리 - 고급편 > 전략 패턴 (시작, 예제 1) (0) | 2024.05.10 |
Comments