IT/Spring

Reactor defer란

물통꿀꿀이 2020. 11. 28. 15:58

Reactor의 defer에 대해 알아보려고 한다.

public static <T> Mono<T> defer(Supplier<? extends Mono<? extends T>> supplier)

defer의 코드 정의는 위와 같다. Mono 값을 가지는 supplier를 인자로 받는다.

사실 코드 정의는 그렇다쳐도 defer라는 네이밍만 봐도 무언가 작업을 지연해서 처리하는 메소드라고 짐작할 수 있다.

 

관련 문서를 살펴보면,

Create a Mono provider that will supply a target Mono to subscribe to for each Subscriber downstream.

즉, downstream에 Mono provider를 만들어서 보낸다. 이 말이 이해가 잘 되지 않을 수 있으니 마블 다이어그램을 보도록 하자.

전체적으로 subscribe가 2번인데, 바깥에서 안쪽에서 각각 한 번씩 일어난다.

(바깥에서 subscribe가 발생한 이후에 defer 내부에서 supplier에 다시 한 번 subscribe)

 

Reactor이기 때문에 조금 어렵게 느낄 수도 있지만, 사실상 lazy 기능과 비슷하다.

(코틀린이라면 lateinit 과 같은 느낌??)

한 번 예시 코드를 살펴보자.

int a = 5;
@Override
public void run(String... args) throws Exception {

    Mono<Integer> monoJust = Mono.just(a);
    Mono<Integer> monoDefer = Mono.defer(() -> Mono.just(a));

    monoJust.subscribe(integer1 -> System.out.println(integer1));
    monoDefer.subscribe(integer1 -> System.out.println(integer1));

    a = 7;
    monoJust.subscribe(integer1 -> System.out.println(integer1));
    monoDefer.subscribe(integer1 -> System.out.println(integer1));
}

just와 defer를 비교한 것이다.

just는 알다시피 값을 바로 emit하는 것인데, 위 코드를 실행시켜보면, 아래의 결과 값이 나온다.

5, 5, 5, 7

비슷한 내용으로 switchIfEmpty가 있다.

말 그대로 비어있을 때, 새로운 값을 반환하는 메소드인데 just와 defer에 따라 내부 동작 방식이 조금 다르다.

Mono.just("foo")
    .switchIfEmpty(Mono.just("bar"))
    .subscribe();
}

 

Mono.just("foo")
        .switchIfEmpty(Mono.defer(() -> Mono.just("bar")))
        .subscribe();
}

먼저 첫 번째 코드는 Mono.just("foo") 값이 emit 되어 있지 않더라도 Mono.just("bar")는 호출 될 때마다 emit 한다. (물론 결과는 반영되지 않는다.) 두 번째 코드는 empty 값이라면 그제서야 defer 안에 있는 Mono.just를 실행한다. 이는 defer 동작이 subscribe에 의해 동작하기 때문이다.

 

결과적으로 defer를 사용하면서 쓸데없는 호출을 막고 유연하게 flow를 만들 수 있다.

참고로 swtchIfEmpty의 extension을 사용하게 되면 defer가 내장되어 있기 때문에 굳이 Mono.defer()를 사용하지 않아도 된다. (아래 예시 참조)

Mono.just("foo")
        .switchIfEmpty { Mono.just("bar")) }
        .subscribe();
}

 

Reference

- stackoverflow.com/questions/55955567/what-does-mono-defer-do

- wonwoo.ml/index.php/post/category/web/spring