Spring 핵심원리 고급편 - Template Callback 패턴

목차

콜백이란

콜백, 콜에프터 함수란 다른 코드의 인수로서 넘겨주는 실행 가능한 코드
콜백을 넘겨받는 코드는 이 콜백을 필요에 따라 즉시 실행할 수 있고, 아니면 나중에 실행할 수 있다.

public interface Callback {
void call();
}
@Slf4j
public class TimeLogTemplate {

public void execute(Callback callback){
long startTime = System.currentTimeMillis();

// 비즈니스 로직 실행
callback.call();
// 비즈니스 로직 종료

long endTime = System.currentTimeMillis();
long resultTime = endTime - startTime;
log.info("resultTime = {}", resultTime);
}
}

Template Callback Pattern 실행

직접적으로 Callback 객체내 call 메소드를 실행하는 것이 아닌 TimeLogTemplate 객체에서 execute 메소드를 실행하게 되면 Callback 객체를 넘겨주고 execute 내에서 Callback 객체의 call 메소드가 실행된다.

@Slf4j
public class TemplateCallbackTest {

@Test
void callbackV1(){
TimeLogTemplate template = new TimeLogTemplate();
template.execute(new Callback() {
@Override
public void call() {
log.info("비즈니스 로직 1 실행");
}
});

// 람다식 적용
template.execute(() -> log.info("비즈니스 로직 2 실행"));
}
}

Template Callback Pattern 적용

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;
}
}
}
@RestController
public class OrderControllerV5 {

private final OrderServiceV5 orderService;
private final TraceTemplate template;

public OrderControllerV5(OrderServiceV5 orderService, LogTrace logTrace) {
this.orderService = orderService;
this.template = new TraceTemplate(logTrace);
}

@GetMapping("/v5/request")
public String request(String itemId){

return template.execute("OrderController.request()", new TraceCallback<String>() {
@Override
public String call() {
orderService.orderItem(itemId);
return "ok";
}
});
}
}
@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;
});
}
}
@Repository
public class OrderRepositoryV5 {

private final TraceTemplate template;

public OrderRepositoryV5(LogTrace logTrace) {
this.template = new TraceTemplate(logTrace);
}

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 (InterruptedException e){
e.printStackTrace();
}
}
}
Share