ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 14장 Operator 4 - peek
    Spring/Webflux 2023. 7. 22. 19:33

    github : https://github.com/bjpublic/Spring-Reactive/tree/main/part2/src/main/java/chapter14/operator_4_peek

     

     

    14.5 Sequence 의 내부 동작 확인을 위한 Operator

    Upstream Publisher 에서 emit 되는 데이터의 변경 없이 부수 효과 (side effect) 만을 수행하기 위한 Operator 들로,

    doOnXXXX() 패턴으로 많이 쓰입니다.

    Consumer 또는 Runnable 타입의 함수형 인터페이스를 파라미터로 가지기 때문에 별도의 리턴 값이 없습니다

     

    Publisher 내부 동작을 엿볼 수 있으며, 로그를 출력하는 등의 디버깅 용도로 많이 사용됩니다

     

    또한, 데이터 emit 과정에서 error 가 발생하면 해당 에러에 대한 알림을 전송하는 로직등에 사용합니다

     

    부수효과 side effect
    부수 효과는 함수형 프로그래밍에서 자주 언급되는 용어입니다.
    함수형 프로그래밍에서는 함수가 정해진 결과를 돌려주는 것 이외의 어떤 일을 하게되면 부수효과가 있는 함수 라고 부릅니다
    함수형 프로그래밍에서는 외부의 상태를 변경하거나 함수로 전달되는 파라미터의 상태가 변경되는 것 역시 부수 효과가 있다고 말합니다
    또한 함수가 값을 리턴하지 않는 void 형이면 어떤 식으로든 다른 일을 할 수 밖에 없기 때문에 리턴 값이 없는 함수는 부수 효과가 있다고 생각해도 무방합니다.

     

    표 14-2 doOnXXXX() Operator 목록

    operator 설명
    doOnSubscribe() Publisher 가 구독 중일 때 트리거 되는 동작을 추가할 수 있다
    doOnRequest() Publisher 가 요청을 수신할 때 트리거 되는 동작을 추가할 수 있다
    doOnNext() Publisher 가 데이터를 emit 할 때 트리거되는 동작을 추가할 수 있다.
    doOnComplete() Publisher 가 성공적으로 완료되었을 때 트리거되는 동작을 추가할 수 있다.
    doOnError() Publisher 가 에러가 발생한 상태로 종료되었을 때 트리거되는 동작을 추가할 수 있다.
    doOnCancel() Publisher 가 취소되었을 때 트리거되는 동작을 추가할 수 있다.
    doOnTerminate() Publisher 가 성공적으로 완료되었을 때 또는 에러가 발생한 상태로 종료되었을 때 트리거되는 동작을 추가할 수 있다
     - complete + error 
    doOnEach() Publisher 가 데이터를 emit 할 때, 성공적으로 완료되었을 때, 에러가 발생한 상태로 종료되었을 때 트리거되는 동작을 추가할 수 있다.
    -  emit(onNext) +  complete + error
    doOnDiscard() Upstream 에 있는 전체 Operator 체인의 동작 중에서 Operator 에 의해 폐기되는 요소를 조건부로 정리할 수 있습니다.
    -  backpressure 의 discard
    doAfterTerminate() Downstream 을 성공적으로 완료한 직후 또는 에러가 발생하여 Publisher 가 종료된 직후에 트리거되는 동작을 추가할 수 있다.
    doFirst() Publisher 가 구독되기 전에 트리거되는 동작을 추가할 수 있다.
    doFinally() 에러를 포함해서 어떤 이유이든 간에 Publisher 가 종료된 후 트리거되는 동작을 추가할 수 있다.

    코드 14-42 doOnXXXX() 예제

    public static void main(String[] args) {
      Flux.range(1, 5)
          .doFinally(signalType -> log.info("# doFinally 1: {}", signalType))
          .doFinally(signalType -> log.info("# doFinally 2: {}", signalType))
          .doOnNext(data -> log.info("# range > doOnNext(): {}", data))
          .doOnRequest(data -> log.info("# doOnRequest: {}", data))
          .doOnSubscribe(subscription -> log.info("# doOnSubscribe 1"))
          .doFirst(() -> log.info("# doFirst()"))
          .filter(num -> num % 2 == 1)
          .doOnNext(data -> log.info("# filter > doOnNext(): {}", data))
          .doOnComplete(() -> log.info("# doOnComplete()"))
          .subscribe(new BaseSubscriber<>() {
            @Override
            protected void hookOnSubscribe(Subscription subscription) {
              request(1);
            }
    
            @Override
            protected void hookOnNext(Integer value) {
              log.info("# hookOnNext: {}", value);
              request(1);
            }
          });
    }
    
    // result
    > Task :Example14_42.main()
    19:20:43.335 [main] reactor.util.Loggers DEBUG- Using Slf4j logging framework
    19:20:43.344 [main] c.operator_4_peek.Example14_42 INFO - # doFirst()
    19:20:43.353 [main] c.operator_4_peek.Example14_42 INFO - # doOnSubscribe 1
    19:20:43.354 [main] c.operator_4_peek.Example14_42 INFO - # doOnRequest: 1
    19:20:43.355 [main] c.operator_4_peek.Example14_42 INFO - # range > doOnNext(): 1
    19:20:43.356 [main] c.operator_4_peek.Example14_42 INFO - # filter > doOnNext(): 1
    19:20:43.356 [main] c.operator_4_peek.Example14_42 INFO - # hookOnNext: 1
    19:20:43.356 [main] c.operator_4_peek.Example14_42 INFO - # doOnRequest: 1
    19:20:43.356 [main] c.operator_4_peek.Example14_42 INFO - # range > doOnNext(): 2
    19:20:43.356 [main] c.operator_4_peek.Example14_42 INFO - # range > doOnNext(): 3
    19:20:43.357 [main] c.operator_4_peek.Example14_42 INFO - # filter > doOnNext(): 3
    19:20:43.357 [main] c.operator_4_peek.Example14_42 INFO - # hookOnNext: 3
    19:20:43.357 [main] c.operator_4_peek.Example14_42 INFO - # doOnRequest: 1
    19:20:43.357 [main] c.operator_4_peek.Example14_42 INFO - # range > doOnNext(): 4
    19:20:43.357 [main] c.operator_4_peek.Example14_42 INFO - # range > doOnNext(): 5
    19:20:43.357 [main] c.operator_4_peek.Example14_42 INFO - # filter > doOnNext(): 5
    19:20:43.358 [main] c.operator_4_peek.Example14_42 INFO - # hookOnNext: 5
    19:20:43.358 [main] c.operator_4_peek.Example14_42 INFO - # doOnRequest: 1
    19:20:43.358 [main] c.operator_4_peek.Example14_42 INFO - # doOnComplete()
    19:20:43.358 [main] c.operator_4_peek.Example14_42 INFO - # doFinally 2: onComplete
    19:20:43.359 [main] c.operator_4_peek.Example14_42 INFO - # doFinally 1: onComplete

    doFirst() 가 가장 먼저 실행되며

    doOnSubscribe()

    doOnRequest()

    doOnNext

    hookOnNext 

    순으로 실행됩니다

     

    종료될때는

    doOnComplete()

    doFinally  순서로 실행되는데 역순으로 do Finally 2 가 먼저 실행됩니다.

     

    'Spring > Webflux' 카테고리의 다른 글

    14장 Operator 6 - time  (0) 2023.07.26
    14장 Operator 5 - Error  (0) 2023.07.22
    14장 Operator 3 - transformation  (0) 2023.07.16
    14장 Operator 2 - filter  (0) 2023.07.09
    14장 Operator 1 - Sequence 생성  (0) 2023.07.08

    댓글

Designed by Tistory.