오봉이와 함께하는 개발 블로그

스프링 핵심 원리 - 고급편 > 템플릿 콜백 패턴 (시작, 예제) 본문

BE/Spring

스프링 핵심 원리 - 고급편 > 템플릿 콜백 패턴 (시작, 예제)

오봉봉이 2024. 5. 10. 00:20
728x90

템플릿 콜백 패턴 - 시작

ContextV2는 변하지 않는 템플릿 역할을 하고, 변하는 부분은 파라미터로 넘어온 Strategy의 구현체이다.
이렇게 다른 코드의 인수로서 넘겨주는 실행 가능한 코드를 콜백(callback)이라 한다.

예시를 보면

context.execute(new StrategyLogic1());

context.execute(new Strategy() {
        @Override
        public void call() {
            log.info("비즈니스 로직1 실행"); 
        }
     });

context.execute(() -> log.info("비즈니스 로직1 실행"));

위 코드에서 execute()의 인자로 넘겨주는 것을 콜백이라 한다.

콜백 정의

프로그래밍에서 콜백(callback) 또는 콜애프터 함수(call-after function)는 다른 코드의 인수로서 넘겨주는 실행 가능한 코드를 말한다. 콜백을 넘겨받는 코드는 이 콜백을 필요에 따라 즉시 실행할 수도 있고, 아니면 나중에 실행할 수도 있다.

쉽게 이야기해서 callback은 코드가 호출(call)은 되는데 코드를 넘겨준 곳의 뒤(back)에서 실행된다는 뜻이다.
ContextV2 예제에서 콜백은 Strategy이다.
여기에서는 클라이언트에서 직접 Strategy를 실행하는 것이 아니라, 클라이언트가 ContextV2.execute(..)를 실행할 때 Strategy를 넘겨주고, ContextV2뒤에서 Strategy가 실행된다.

자바에서의 콜백

  • 자바 언어에서 실행 가능한 코드를 인수로 넘기려면 객체가 필요하다.
    • 자바8부터는 람다를 사용할 수 있다.
  • 자바 8 이전에는 보통 하나의 메소드를 가진 인터페이스를 구현하고, 주로 익명 내부 클래스를 사용했다.
  • 최근에는 주로 람다를 사용한다.

템플릿 콜백 패턴

  • 스프링에서는 ContextV2와 같은 방식의 전략 패턴을 템플릿 콜백 패턴이라 한다.
    • 전략 패턴에서 Context가 템플릿 역할을 하고, Strategy부분이 콜백으로 넘어온다 생각하면 된다.
  • 참고로 템플릿 콜백 패턴은 GOF 패턴은 아니고, 스프링 내부에서 이런 방식을 자주 사용하기 때문에, 스프링 안에서만 이렇게 부른다.
    • 전략 패턴에서 템플릿과 콜백 부분이 강조된 패턴이라 생각하면 된다.
  • 스프링에서는 JdbcTemplate, RestTemplate, TransactionTemplate, RedisTemplate처럼 다양한 템플릿 콜백 패턴이 사용된다.
    • 스프링에서 이름에 XxxTemplate가 있다면 템플릿 콜백 패턴으로 만들어져 있다 생각하면 된다.

image

템플릿 콜백 패턴 - 예제

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

  public void execute(Callback callback) {
    long startTime = System.currentTimeMillis();
    // logic start
    callback.call();
    // logic end
    long endTime = System.currentTimeMillis();
    long resultTime = endTime - startTime;
    log.info("resultTime = {}", resultTime);
  }

}
@Slf4j
public class TemplateCallbackTest {

  @Test
  void callbackV1() {
    TimeLogTemplate template = new TimeLogTemplate();

    template.execute(new Callback() {
      @Override
      public void call() {
        log.info("logic 1");
      }
    });

    template.execute(new Callback() {
      @Override
      public void call() {
        log.info("logic 2");
      }
    });
  }

  @Test
  void callbackV2() {
    TimeLogTemplate template = new TimeLogTemplate();

    template.execute(() -> log.info("logic 1"));
    template.execute(() -> log.info("logic 2"));
  }
}

별도 클래스를 사용해도 무방하고, 익명 클래스 혹은 람다 또한 사용 가능하다.

 

출처: 김영한 지식공유자님의 스프링 핵심 원리 고급편

728x90
Comments