(시청일 : 20170114)



스프링 5.0 WebFlux에서 사용되는 Reactor의 Mono의 기본 동작방식을 살펴봅니다.



■ 예제 1
package toby;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@SpringBootApplication
@RestController
@Slf4j
public class Toby013Application {
    @GetMapping("/")
    Mono<String> hello() {
        return Mono.just("Hello WebFlux").log(); // Publisher -> (Publisher) -> (Publisher) -> Subscriber
    }
    public static void main(String[] args) {
        SpringApplication.run(Toby013Application.class, args);
    }
}


<결과>
2018-01-21 17:15:04.761  INFO 8148 --- [ctor-http-nio-2] reactor.Mono.Just.1                      : | onSubscribe([Synchronous Fuseable] Operators.ScalarSubscription)
2018-01-21 17:15:04.764  INFO 8148 --- [ctor-http-nio-2] reactor.Mono.Just.1                      : | request(1)
2018-01-21 17:15:04.764  INFO 8148 --- [ctor-http-nio-2] reactor.Mono.Just.1                      : | onNext(Hello WebFlux)
2018-01-21 17:15:04.787  INFO 8148 --- [ctor-http-nio-2] reactor.Mono.Just.1                      : | request(1)
2018-01-21 17:15:04.787  INFO 8148 --- [ctor-http-nio-2] reactor.Mono.Just.1                      : | request(31)
2018-01-21 17:15:04.787  INFO 8148 --- [ctor-http-nio-2] reactor.Mono.Just.1                      : | onComplete()
2018-01-21 17:15:05.264  INFO 8148 --- [ctor-http-nio-2] reactor.Mono.Just.1                      : | cancel()



■ 예제 2
package toby;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@SpringBootApplication
@RestController
@Slf4j
public class Toby013Application {
    @GetMapping("/")
    Mono<String> hello() {
        log.info("pos1");
        Mono m = Mono.just("Hello WebFlux").log(); // Publisher -> (Publisher) -> (Publisher) -> Subscriber
        log.info("pos2");
        return m;
    }
    public static void main(String[] args) {
        SpringApplication.run(Toby013Application.class, args);
    }
}




<결과>
2018-01-21 17:18:46.265  INFO 13388 --- [ctor-http-nio-2] toby.Toby013Application                  : pos1
2018-01-21 17:18:46.268  INFO 13388 --- [ctor-http-nio-2] toby.Toby013Application                  : pos2
2018-01-21 17:18:46.284  INFO 13388 --- [ctor-http-nio-2] reactor.Mono.Just.1                      : | onSubscribe([Synchronous Fuseable] Operators.ScalarSubscription)
2018-01-21 17:18:46.285  INFO 13388 --- [ctor-http-nio-2] reactor.Mono.Just.1                      : | request(1)
2018-01-21 17:18:46.286  INFO 13388 --- [ctor-http-nio-2] reactor.Mono.Just.1                      : | onNext(Hello WebFlux)
2018-01-21 17:18:46.307  INFO 13388 --- [ctor-http-nio-2] reactor.Mono.Just.1                      : | request(1)
2018-01-21 17:18:46.308  INFO 13388 --- [ctor-http-nio-2] reactor.Mono.Just.1                      : | request(31)
2018-01-21 17:18:46.308  INFO 13388 --- [ctor-http-nio-2] reactor.Mono.Just.1                      : | onComplete()
2018-01-21 17:18:46.746  INFO 13388 --- [ctor-http-nio-2] reactor.Mono.Just.1                      : | cancel()




■ 예제 3
package toby;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@SpringBootApplication
@RestController
@Slf4j
public class Toby013Application {
    @GetMapping("/")
    Mono<String> hello() {
        log.info("pos1");
        Mono m = Mono.just("Hello WebFlux").doOnNext(c->log.info(c)).log(); // Publisher -> (Publisher) -> (Publisher) -> Subscriber
        log.info("pos2");
        return m;
    }
    public static void main(String[] args) {
        SpringApplication.run(Toby013Application.class, args);
    }
}




<결과>
2018-01-21 17:20:50.096  INFO 13748 --- [ctor-http-nio-2] toby.Toby013Application                  : pos1
2018-01-21 17:20:50.099  INFO 13748 --- [ctor-http-nio-2] toby.Toby013Application                  : pos2
2018-01-21 17:20:50.115  INFO 13748 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onSubscribe([Fuseable] FluxPeekFuseable.PeekFuseableSubscriber)
2018-01-21 17:20:50.117  INFO 13748 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | request(1)
2018-01-21 17:20:50.117  INFO 13748 --- [ctor-http-nio-2] toby.Toby013Application                  : Hello WebFlux
2018-01-21 17:20:50.117  INFO 13748 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onNext(Hello WebFlux)
2018-01-21 17:20:50.138  INFO 13748 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | request(1)
2018-01-21 17:20:50.138  INFO 13748 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | request(31)
2018-01-21 17:20:50.139  INFO 13748 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onComplete()
2018-01-21 17:20:50.229  INFO 13748 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | cancel()




■ 예제 4
package toby;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@SpringBootApplication
@RestController
@Slf4j
public class Toby013Application {
    @GetMapping("/")
    Mono<String> hello() {
        log.info("pos1");
        Mono m = Mono.just(generateHello()).doOnNext(c->log.info(c)).log(); // Publisher -> (Publisher) -> (Publisher) -> Subscriber
        log.info("pos2");
        return m;
    }
    private String generateHello() {
        log.info("method generateHello()");
        return "Hello Mono";
    }
    public static void main(String[] args) {
        SpringApplication.run(Toby013Application.class, args);
    }
}




<결과>
2018-01-21 17:26:20.531  INFO 14112 --- [ctor-http-nio-2] toby.Toby013Application                  : pos1
2018-01-21 17:26:20.531  INFO 14112 --- [ctor-http-nio-2] toby.Toby013Application                  : method generateHello()
2018-01-21 17:26:20.534  INFO 14112 --- [ctor-http-nio-2] toby.Toby013Application                  : pos2
2018-01-21 17:26:20.552  INFO 14112 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onSubscribe([Fuseable] FluxPeekFuseable.PeekFuseableSubscriber)
2018-01-21 17:26:20.553  INFO 14112 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | request(1)
2018-01-21 17:26:20.553  INFO 14112 --- [ctor-http-nio-2] toby.Toby013Application                  : Hello Mono
2018-01-21 17:26:20.553  INFO 14112 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onNext(Hello Mono)
2018-01-21 17:26:20.575  INFO 14112 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | request(1)
2018-01-21 17:26:20.575  INFO 14112 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | request(31)
2018-01-21 17:26:20.575  INFO 14112 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onComplete()
2018-01-21 17:26:20.755  INFO 14112 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | cancel()


■ 예제 5
package toby;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@SpringBootApplication
@RestController
@Slf4j
public class Toby013Application {
    @GetMapping("/")
    Mono<String> hello() {
        log.info("pos1");
        Mono m = Mono.fromSupplier(() -> generateHello()).doOnNext(c->log.info(c)).log(); // Publisher -> (Publisher) -> (Publisher) -> Subscriber
        log.info("pos2");
        return m;
    }
    private String generateHello() {
        log.info("method generateHello()");
        return "Hello Mono";
    }
    public static void main(String[] args) {
        SpringApplication.run(Toby013Application.class, args);
    }
}





<결과>
2018-01-21 17:29:04.571  INFO 13256 --- [ctor-http-nio-2] toby.Toby013Application                  : pos1
2018-01-21 17:29:04.575  INFO 13256 --- [ctor-http-nio-2] toby.Toby013Application                  : pos2
2018-01-21 17:29:04.589  INFO 13256 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onSubscribe([Fuseable] FluxPeekFuseable.PeekFuseableSubscriber)
2018-01-21 17:29:04.591  INFO 13256 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | request(1)
2018-01-21 17:29:04.591  INFO 13256 --- [ctor-http-nio-2] toby.Toby013Application                  : method generateHello()
2018-01-21 17:29:04.591  INFO 13256 --- [ctor-http-nio-2] toby.Toby013Application                  : Hello Mono
2018-01-21 17:29:04.591  INFO 13256 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onNext(Hello Mono)
2018-01-21 17:29:04.622  INFO 13256 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | request(1)
2018-01-21 17:29:04.622  INFO 13256 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | request(31)
2018-01-21 17:29:04.623  INFO 13256 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onComplete()



■ 예제 6
package toby;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@SpringBootApplication
@RestController
@Slf4j
public class Toby013Application {
    @GetMapping("/")
    Mono<String> hello() {
        log.info("pos1");
        Mono m = Mono.fromSupplier(() -> generateHello()).doOnNext(c->log.info(c)).log(); // Publisher -> (Publisher) -> (Publisher) -> Subscriber
        m.subscribe();
        log.info("pos2");
        return m;
    }
    private String generateHello() {
        log.info("method generateHello()");
        return "Hello Mono";
    }
    public static void main(String[] args) {
        SpringApplication.run(Toby013Application.class, args);
    }
}





<결과>
2018-01-21 17:33:30.588  INFO 13316 --- [ctor-http-nio-2] toby.Toby013Application                  : pos1
2018-01-21 17:33:30.596  INFO 13316 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onSubscribe([Fuseable] FluxPeekFuseable.PeekFuseableSubscriber)
2018-01-21 17:33:30.598  INFO 13316 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | request(unbounded)
2018-01-21 17:33:30.598  INFO 13316 --- [ctor-http-nio-2] toby.Toby013Application                  : method generateHello()
2018-01-21 17:33:30.598  INFO 13316 --- [ctor-http-nio-2] toby.Toby013Application                  : Hello Mono
2018-01-21 17:33:30.598  INFO 13316 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onNext(Hello Mono)
2018-01-21 17:33:30.599  INFO 13316 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onComplete()
2018-01-21 17:33:30.599  INFO 13316 --- [ctor-http-nio-2] toby.Toby013Application                  : pos2
2018-01-21 17:33:30.612  INFO 13316 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onSubscribe([Fuseable] FluxPeekFuseable.PeekFuseableSubscriber)
2018-01-21 17:33:30.612  INFO 13316 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | request(1)
2018-01-21 17:33:30.612  INFO 13316 --- [ctor-http-nio-2] toby.Toby013Application                  : method generateHello()
2018-01-21 17:33:30.612  INFO 13316 --- [ctor-http-nio-2] toby.Toby013Application                  : Hello Mono
2018-01-21 17:33:30.612  INFO 13316 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onNext(Hello Mono)
2018-01-21 17:33:30.633  INFO 13316 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | request(1)
2018-01-21 17:33:30.633  INFO 13316 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | request(31)
2018-01-21 17:33:30.634  INFO 13316 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onComplete()
2018-01-21 17:33:31.249  INFO 13316 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | cancel()




■ 예제 7
package toby;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@SpringBootApplication
@RestController
@Slf4j
public class Toby013Application {
    @GetMapping("/")
    Mono<String> hello() {
        log.info("pos1");
        String msg = generateHello();
        Mono<String> m = Mono.just(msg).doOnNext(c->log.info(c)).log(); // Publisher -> (Publisher) -> (Publisher) -> Subscriber
        String msg2 = m.block();
        log.info("pos2: " + msg2);
        return m;
    }
    private String generateHello() {
        log.info("method generateHello()");
        return "Hello Mono";
    }
    public static void main(String[] args) {
        SpringApplication.run(Toby013Application.class, args);
    }
}






<결과>
2018-01-21 17:39:20.356  INFO 11348 --- [ctor-http-nio-2] toby.Toby013Application                  : pos1
2018-01-21 17:39:20.356  INFO 11348 --- [ctor-http-nio-2] toby.Toby013Application                  : method generateHello()
2018-01-21 17:39:20.362  INFO 11348 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onSubscribe([Fuseable] FluxPeekFuseable.PeekFuseableSubscriber)
2018-01-21 17:39:20.364  INFO 11348 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | request(unbounded)
2018-01-21 17:39:20.364  INFO 11348 --- [ctor-http-nio-2] toby.Toby013Application                  : Hello Mono
2018-01-21 17:39:20.364  INFO 11348 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onNext(Hello Mono)
2018-01-21 17:39:20.364  INFO 11348 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onComplete()
2018-01-21 17:39:20.365  INFO 11348 --- [ctor-http-nio-2] toby.Toby013Application                  : pos2: Hello Mono
2018-01-21 17:39:20.381  INFO 11348 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onSubscribe([Fuseable] FluxPeekFuseable.PeekFuseableSubscriber)
2018-01-21 17:39:20.381  INFO 11348 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | request(1)
2018-01-21 17:39:20.381  INFO 11348 --- [ctor-http-nio-2] toby.Toby013Application                  : Hello Mono
2018-01-21 17:39:20.381  INFO 11348 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onNext(Hello Mono)
2018-01-21 17:39:20.407  INFO 11348 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | request(1)
2018-01-21 17:39:20.407  INFO 11348 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | request(31)
2018-01-21 17:39:20.407  INFO 11348 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onComplete()
2018-01-21 17:39:20.579  INFO 11348 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | cancel()


- block : publisher가 제공하는 결과값을 꺼내서 Mono나 Flux 같은 컨테이너를 제거하고 값을 넘겨주는 것이 목적.


■ 예제 8
package toby;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@SpringBootApplication
@RestController
@Slf4j
public class Toby013Application {
    @GetMapping("/")
    Mono<String> hello() {
        log.info("pos1");
        String msg = generateHello();
        Mono<String> m = Mono.just(msg).doOnNext(c->log.info(c)).log(); // Publisher -> (Publisher) -> (Publisher) -> Subscriber
        String msg2 = m.block();
        log.info("pos2: " + msg2);
        return Mono.just(msg2);
    }
    private String generateHello() {
        log.info("method generateHello()");
        return "Hello Mono";
    }
    public static void main(String[] args) {
        SpringApplication.run(Toby013Application.class, args);
    }
}




<결과>
2018-01-21 17:48:23.009  INFO 13012 --- [ctor-http-nio-2] toby.Toby013Application                  : pos1
2018-01-21 17:48:23.009  INFO 13012 --- [ctor-http-nio-2] toby.Toby013Application                  : method generateHello()
2018-01-21 17:48:23.015  INFO 13012 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onSubscribe([Fuseable] FluxPeekFuseable.PeekFuseableSubscriber)
2018-01-21 17:48:23.016  INFO 13012 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | request(unbounded)
2018-01-21 17:48:23.016  INFO 13012 --- [ctor-http-nio-2] toby.Toby013Application                  : Hello Mono
2018-01-21 17:48:23.017  INFO 13012 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onNext(Hello Mono)
2018-01-21 17:48:23.017  INFO 13012 --- [ctor-http-nio-2] reactor.Mono.PeekFuseable.1              : | onComplete()
2018-01-21 17:48:23.018  INFO 13012 --- [ctor-http-nio-2] toby.Toby013Application                  : pos2: Hello Mono




+ Recent posts