728x90


@SpringBootApplication
public class Chapter13Application {
public static void main(String[] args) {
//Tomcat을 기본으로 사용하는 것이 아닌, netty가 실행이된다.
//비동기 non-blocking 에 사용되는 서버인 netty가 기본적으로 실행되는 것을 확인 할 수 있다.
SpringApplication.run(Chapter13Application.class, args);
}
}
- dependency를 추가할 때는 spring-web과 spring-webflux를 같이 import 하지 말자(webflux에 web을 포함하고 있음)
- 기본적으로 spring-webflux의 dependency만 있다면, 서버는 톰캣이 아닌 netty가 실행되는 것을 알 수 있다.
- web도 같이 dependency에 추가하면, 톰캣이 뜬다(톰캣 우선순위가 더 높다)
Hello Mono
@RestController
public static class MyController{
@GetMapping("/")
Mono<String> hello(){
return Mono.just("Hello WebFlux"); //new로 생성하면 안되고, static 패턴인 just로 생성해야한다.
}
}
- Mono를 반환해 비동기 적으로 Hello Webflux를 출력할 수 있다.
Mono에 대해 자세히 살펴보자!
log() 찍기
@GetMapping("/")
Mono<String> hello(){
return Mono.just("Hello WebFlux")
// Publisher -> (Publisher) -> (Publisher) -> Subscriber 이런 패턴으로 구현된 것이 Reactive 방식이다.
.log()
;
}

- onSubscribe를 먼저 실행( 누가 할까 -> Spring)
- onNext()로 Mono로 생성한 데이터를 전달하고, onComplete를 실행하는 것을 확인할 수 있다.
비동기식으로 동작하는 Mono 확인하기
@GetMapping("/")
Mono<String> hello(){
log.info("pos1");
Mono m = Mono.just("Hello WebFlux").doOnNext(c -> log.info(c)).log(); //이전에 동기식으로 동작한다면, 해당 코드 먼저 실행되야 하지만, log가 찍히고 해당 로그가 찍힌다.
String msg = generateHello();
Mono m = Mono.just(msg).doOnNext(c -> log.info(c)).log(); //pos1 -> method generateHello() -> pos2 실행후 비동기실행 로그가 출력된다.
log.info("pos2");
return m;
}
private String generateHello() {
log.info("method generateHello()");
return "Hello Mono";
}

- 코드는 동기적으로 동작하는 것이지만, 실행되는 메서드들은 비동기적으로(데이터가 전달을 받게 되면) 실행되는 것이다.
- 만약 어떤 값을 반환하는 메서드가 just안에 들어가게 된다면 어떤 식으로 코드가 실행될까?
- just는 이미 준비된 Publishing 한 데이터를 가지고, 비동기로 실행되기 때문에 어떤 값을 반환하는 메서드가 호출되고, 결과를 얻은 다음 그 값을 reactive 방식으로 처리할 것이다 -> 어떤 값을 반환하는 메서드가 먼저 실행
callback을 통해 호출되는 Mono
@GetMapping("/")
Mono<String> hello() {
log.info("pos1");
//fromSupplier = 파라미터는X 리턴값만 있다.
Mono m = Mono.fromSupplier(() -> generateHello()).doOnNext(c -> log.info(c)).log();
log.info("pos2");
return m;
}

- fromSupplier 메서드는 파라미터가 없고, 리턴 값만 받는 함수이다.
- 비동기로, 함수를 실행시키고 싶다면(함수를 callback에서 호출하고 싶을 경우)는 위와 같이 fromSupplier를 사용하면 된다.
- 람다로 전달된 함수는 Publisher로 Subscribe를 호출하게 되었을 때, 실행된다.
상황: subscribe를 메서드에서 실행 후, 리턴하면 어떻게 될까?
- subscribe를 한번 했으니 리턴시 오류가 난다
- subscribe를 한번 했으니 실행 시 오류는 없지만 실행 x
- subscribe를 2번 호출이 된다.
@GetMapping("/")
Mono<String> hello() {
log.info("pos1");
Mono m = Mono.fromSupplier(() -> generateHello()).doOnNext(c -> log.info(c)).log();
m.subscribe();
log.info("pos2");
return m;
}

- 3번 결과가 실행이 된다.
- pos1 로그를 출력 후, Mono의 실행을 진행하고(m.subcribe에서 진행) 후, pos2 를 출력 후, 스프링이 다시 리턴 받은 Mono의 subscribe를 호출한다
- Cold / Hot 소스코드에 따라 다르게 동작된다.
- Cold 소스 코드(DB, 메서드를 통해 넘어오는 데이터) Publisher : Mono의 체인을 처음부터 호출한다.
- Hot 소스 코드(실시간으로 일어나는 이벤트) Publisher: 구독하는 데이터의 시점부터 시작해서, 체인닝을 시작한다
block() : 현재의 Webflux에서 지원하지 않는 기능
@GetMapping("/")
Mono<String> hello() {
log.info("pos1");
String msg = generateHello();
Mono<String> m = Mono.just(msg).doOnNext(c -> log.info(c)).log();
String msg2 = m.block(); //Mono 체인으로 동작시킬 것이 아닌 String 으로 받을 때 사용한다.
log.info("pos2");
//return m;
return Mono.just(msg2);
}

- Mono에서 전달받은 데이터를 출력하기 위해 m.block()을 사용하였다.
- 이럴 경우 Mono에서 실행시킬 함수를 실행시켜, block()에 값을 전달
- subscribe를 실행시키기도 전에 m.block()을 호출한 순간, 값을 가지고 와야 하기 때문에 함수를 실행 할 수 밖에 없다
- 비동기 함수에서 get()을 사용한 것과 같다
- callback과 같이 비동기를 사용한 것이 아니기 때문에 더 이상 지원하지 않는 것으로 보인다.(오류가 발생한다)
- block()을 통해 값을 읽어 온 뒤, 해당 다시 mono를 리턴하면, subscribe가 한번 더 호출되어 코드가 또 실행될 수 있는데, Mono.just()로 block()된 데이터를 반환하여, 한 번만 실행하도록 해야 한다.
- 비동기 작업은 모두 Mono로 연결해서 동작시켜야 하기 때문에 block() 기능은 웬만하면 사용하지 말자!!
Mono를 사용하면, 많은 비동기 작업을 조합시킬 수 있고, 오류를 쉽게 처리하고 복구할 수 있기 때문에 Mono를 적극적으로 활용하자!
728x90
'Toby의 ReactiveProgramming' 카테고리의 다른 글
| Spring 6의 새로운 HTTP Interface와 3가지 REST Clients (0) | 2023.06.06 |
|---|---|
| Flux의 특징과 활용방법 (0) | 2022.08.30 |
| WebFlux (0) | 2022.08.28 |
| CompletableFuture (0) | 2022.08.27 |
| AsyncRestTemplate의 콜백 헬과 중복 작업 문제 (0) | 2022.08.26 |