1. Flux의 개념

- 기존의 동기식 프로그램은 한 개의 작업이 끝나고 다른 작업을 실행하는 Blocking 방식의 프로그래밍

- 그런데, 한 번에 여러개의 작업을 계속 처리하는 것을 Non-blocking 방식의 프로그래밍. 

- Flux는 데이터 스트림을 통해 작업을 비동기적으로 처리하고, 데이터가 준비되면 그 즉시 처리할 수 있도록 해준다. => 반응성이 뛰어나고 많은 양의 데이터를 처리하는 것에 효율적임.

 

1-2. Flux와 Mono의 차이

- Flux는 0개 이상의 값을 가질 수 있고, Mono는 0개 또는 1개의 값을 가진다.

- Reactive Stream은 Publisher가 Subscriber에게 데이터를 제공하는 개념이며, Flux와 Mono는 이러한 Publisher의 구현.

 

2. List와 뭐가 다를까 ?

-  동기적 상황에서는 List를 쓰고, 비동기적 상황에서는 Flux or Mono를 사용한다.

-  데이터를 조금씩 처리할 수 있어서 메모리 사용량을 줄일 수 있다. 

   List는 1부터 100까지의 수를 한 번에 저장해놓고 필요한 순간에 가져와서 사용하지만 Mono와 Flux는 필요한 순간에 값을 생성해서

   메모리를 줄일 수 있다고 한다.

- 비동기적 또는 리액티브한 프로그래밍에서 더 유연하고 확장가능한 해결책을 제시해준다고 한다. 

 

3. 기본적인 Flux 사용법

// 1. 그냥 생성
Flux<String> flux1 = Flux.just("Apple", "Banana", "Orange");

// 2. Iterable 객체를 기반으로 Flux 생성
List<String> fruits = Arrays.asList("Apple", "Banana", "Orange");
Flux<String> flux2 = Flux.fromIterable(fruits);

// 3. 빈 Flux 생성
Flux<String> flux3 = Flux.empty();

// 4. 주어진 범위 내의 값을 생성
Flux<Integer> flux4 = Flux.range(1, 5);

// 5. 주어진 Supplier or BiFunction을 사요ㅕㅇ해서 값을 생성하는 Flux를 생성
Flux<String> flux5 = Flux.generate(
        () -> 0, // 상태(초기값)를 생성하는 역할인 Supplier
        (state, sink)   -> {
            sink.next("Value_" + state);
            if(state == 5 ) sink.complete();
            return state +1;
        }
);

// 6. 주어진 FluxSink를 사용하여 값을 생성하는 Flux를 생성. 주의! 직접 사용하기 보다는 'FluxSink'를 사용하여 커스텀 발행 로직을 구현할 때 사용.
Flux<String> flux6 = Flux.create(sink -> {
    sink.next("Apple");
    sink.next("Banana");
    sink.complete();
});

/* FluxSink
    next()
    error()
    complete()
*/

// 인덱스를 뽑기.
flux1.elementAt(1)
        .subscribe(System.out::println);

// 순차적으로 뽑기.
// 첫 번째, 데이터 핸들링 함수: Flux or Mono에서 발생한 데이터를 처리
// 두 번쨰, 에러 핸들링 함수: Flux or Mono에서 에러가 발생했을 때 처리할 작업
// 세 번째, 완료 핸들링 함수 : Flux or Mono에서 데이터 발행이 완료되었을 떄 실행할 작업
flux6.subscribe(
        data -> System.out.println(data),
        error -> System.err.println("Error occurred: " + error),
        () -> System.out.println("Completed!")
);

 

 

4. 단점

 - 비동기적이고 이벤트 기반의 프로그래밍을 지원하기 떄문에 코드가 복잡해질 수 있다. 

 - 당연히 비동기적이기 때문에 순서보장이 어렵다 

 - 따라서 이벤트 루프나 쓰레드 풀이 필요할 수 있기때문에 오버헤드가 발생할 수 있다.

 - 스트림을 처리하는 동안 리소스 누수가 발생할 수 있다. (예를 들어 create에서 complete()을 안 해준다..)

=> 이런 단점을 커버하기 위해 적절한 코드 사용이 필요한데 기존의 동기식 프로그래밍과 많이 다르기때문에 학습곡선이 높다!