75일차 [Spring WebFlux] 리액티브프로그래밍

2022. 8. 11. 13:43카테고리 없음

리액티브 시스템(Reactive System)이란?

리액티브 시스템은 한마디로 반응을 잘하는 시스템을 의미합니다.

그렇다면 여기서의 반응은 무엇에 대한 반응일까요?

 

바로 리액티브 시스템을 이용하는 클라이언트의 요청에 반응을 잘하는 시스템을 의미합니다.

 

마지막으로 한 가지 질문에 대해서 한 번 더 생각해 봅시다.

 

클라이언트의 요청에 반응을 잘 하는’이라는 말은 도대체 어떤 의미로 받아들일 수 있을까요?

 

‘리액션이 좋은 사람’은 상대방의 질문이나 의견에 반응을 잘해서 “아 그러시군요.”, “그렇죠. 맞습니다.”, “아, 그래요?”, “대단하신데요?” 등의 표현들을 통해 바로 바로 반응을 해줍니다.

물론 리액션이 좋은 사람의 반응에는 상대방의 이야기에 대한 구체적인 의견이 들어있을 수도 있지만 일단은 먼저 상대방의 이야기에 반응부터 해주고 구체적인 의견이나 질문 등은 나중에 이어지는 경우가 많습니다.

 

리액티브 시스템도 이와 유사합니다.

다만 리액티브 시스템 관점에서의 반응은 쓰레드의 Non-Blocking과 관련이 있습니다.

 

리액티브 시스템은 클라이언트의 요청에 대한 응답 대기 시간을 최소화 할 수 있도록 요청 쓰레드가 차단되지 않게 함으로써(Non-Blocking) 클라이언트에게 즉각적으로 반응하도록 구성된 시스템이라고 볼 수 있습니다.

 

그렇다면 리액티브 시스템이 클라이언트의 요청에 즉각적인 반응을 보일 수 있도록 하기 위한 리액티브 시스템만의 어떤한 특징이 있을 것입니다.

 

리액티브 선언문에 나와 있는 리액티브 시스템 설계원칙의 그림을 통해 리액티브 시스템의 특징을 확인해 봅시다.

 

[그림 4-1]은 리액티브 시스템의 설계 원칙을 그림으로 표현한 것입니다.

[그림 4-1]에 나와 있는 용어들을 토대로 리액티브 시스템의 특징을 간단히 살펴 보겠습니다.

 

  • MEANS
    • Message Driven
      • 리액티브 시스템에서는 메시지 기반 통신을 통해 여러 시스템 간에 느슨한 결합을 유지합니다.
  • MEANS는 리액티브 시스템에서 사용하는 커뮤니케이션 수단을 의미합니다.

 

  • FORM
    • Elastic
      • 시스템으로 들어오는 요청량이 적거나 많거나에 상관없이 일정한 응답성을 유지하는 것을 의미합니다.
    • Resillient
      • 시스템의 일부분에 장애가 발생하더라도 응답성을 유지하는 것을 의미합니다.
  • FORM은 메시지 기반 통신을 통해 리액티브 시스템이 어떤 특성을 가지는 구조로 형성되는지를 의미합니다.

 

  • VALUE
    • Responsive
      • 리액티브 시스템은 클라이언트의 요청에 즉각적으로 응답할 수 있어야 함을 의미합니다.
    • Maintainable
      • 클라이언트의 요청에 대한 즉각적인 응답이 지속가능해야 함을 의미합니다.
    • Extensible
      • 클라이언트의 요청에 대한 처리량을 자동으로 확장하고 축소할 수 있어야 함을 의미합니다.
  • 리액티브 시스템의 핵심 가치가 무엇인지를 표현하는 영역입니다.



리액티브 프로그래밍(Reactive Programming)이란?

그렇다면 리액티브 프로그래밍이란 무엇일까요?

 

리액티브 프로그래밍은 한마디로 리액티브 시스템에서 사용되는 프로그래밍 모델을 의미합니다.

 

리액티브 시스템에서의 메시지 기반 통신(Message Driven)은 Non-Blocking 통신과 유기적인 관계를 맺고 있으며, 리액티브 프로그래밍은 Non-Blocking 통신을 위한 프로그래밍 모델입니다.

 

Non-Blocking에 대해서는 뒤에서 자세히 설명합니다.

 

✔ 리액티브 프로그래밍의 특징

 

리액티브 프로그래밍(reactive programming)은 컴퓨팅에서 데이터 스트림과 변화의 전파와 관련된 선언적 프로그래밍 패러다임이다. 이 패러다임을 통해 정적(예: 어레이) 또는 동적(예: 이벤트 이미터) 데이터 스트림을 쉽게 표현할 수 있으며, 또한 변경된 데이터 흐름의 자동 전파를 용이하게 하는 관련 실행 모델 내에 유추된 종속성이 존재함을 전달할 수 있다.

 

 

  • declarative programming paradigm
    • 리액티브 프로그래밍은 선언형 프로그래밍 방식을 사용하는 대표적인 프로그래밍 모델입니다.
    • 명령형 프로그래밍과 선언형 프로그래밍의 차이점에 대해서는 뒤에서 설명하겠습니다.

 

  • data streams and the propagation(전파) of change
    • data streams지속적으로 데이터가 입력으로 들어올 수 있음을 의미하며, 리액티브 프로그래밍에서는 데이터가 지속적으로 발생하는 것 자체를 데이터에 어떤 변경이 발생함을 의미합니다.
    • 그리고 이 변경 자체를 이벤트로 간주하고, 이벤트가 발생할 때 마다 데이터를 계속해서 전달합니다.

 

  • automatic propagation of the changed data flow
    • 앞에서 설명한 data streams and the propagation of change와 같은 의미입니다. 지속적으로 발생하는 데이터를 하나의 데이터 플로우로 보고 데이터를 자동으로 전달합니다.

 

지금 당장 리액티브 프로그래밍은 이런거구나 라고 이해할 수 없을거라고 생각합니다.

리액티브 프로그래밍에 대한 조금 더 구체적인 내용은 코드로 설명할테니 조금만 기다려주세요.



리액티브 스트림즈(Reactive Streams)란?

계속해서 리액티브와 관련된 용어 한가지만 더 살펴보겠습니다.

 

여러분들이 JPA와 JDBC API의 공통점이 무엇인가요? 라는 질문에 정확하게 대답할 수 있다면 리액티브 스트림즈(Reactive Stream)가 의미하는 바를 바로 이해할 수 있을 거라 생각합니다. ^^

 

JPA(Java Persistence API)는 Java 진영에서 사용하는 ORM(Object-Relational Mapping) 기술의 표준 사양(또는 명세, Specification)입니다.

 

그리고 JDBC는 Java 애플리케이션에서 데이터베이스에 액세스하기 위한 표준 사양(또는 명세, Specification)입니다.

 

두 기술의 공통점을 찾았을까요? ^^

그렇다면 리액티브 스트림즈(Reactive Streams)란?

 

맞습니다. 리액티브 스트림즈(Reactive Streams)는 리액티브 프로그래밍을 위한 표준 사양(또는 명세, Specification)입니다.

 

Java에서는 어떤 기술의 표준 사양을 코드로 정의할 경우 일반적으로 Java의 인터페이스(interface)로 정의합니다.

 

그렇다면 리액티브 스트림즈에서 사양으로 정의된 컴포넌트(구성요소)에는 어떤 것들이 있을까요?

 

 

 

✅ 리액티브 스트림즈 컴포넌트

✔ Publisher

public interface Publisher<T> {
    public void subscribe(Subscriber<? super T> s);
}

[코드 4-1] Publisher 인터페이스

Publisher 인터페이스는 데이터 소스로 부터 데이터를 내보내는(emit) 역할을 합니다.

 

Publisher 인터페이스는 코드 4-1과 같이 subscribe() 추상 메서드를 포함하고 있으며,

subscribe()의 파라미터로 전달되는 SubscriberPublisher로부터 내보내진 데이터를 소비하는 역할을 합니다.

 

subscribe() 는 메서드 이름에서도 알 수 있듯이 Publisher가 내보내는 데이터를 수신할 지 여부를 결정하는 구독의 의미를 가지고 있으며, 일반적으로 subscribe()가 호출되지 않으면 Publisher가 데이터를 내보내는 프로세스는 시작되지 않습니다.

 

이 후부터는 Publisher가 데이터를 내보내는 것emit한다라고 표현하겠습니다.

 

✔ Subscriber

public interface Subscriber<T> {
    public void onSubscribe(Subscription s);
    public void onNext(T t);
    public void onError(Throwable t);
    public void onComplete();
}

[코드 4-2] Subscriber 인터페이스

Subscriber 인터페이스는 Publisher로부터 내보내진 데이터를 소비하는 역할을 합니다.

Subscriber네 개의 추상 메서드를 포함하고 있으며, 각 메서드의 역할은 다음과 같습니다.

 

  • onSubscribe(Subscription s)
    • 구독이 시작되는 시점에 호출되며,
    • onSubscribe() 내에서 Publisher에게 요청할 데이터의 개수를 지정하거나 구독 해지 처리를 할 수 있습니다.
  • onNext(T t)
    • Publisher가 데이터를 emit할 때 호출되며, emit된 데이터를 전달 받아서 소비할 수 있습니다.
  • onError(Throwable t)
    • Publisher로부터 emit된 데이터가 Subscriber에게 전달되는 과정에서 에러가 발생할 경우에 호출됩니다.
  • onComplete()
    • emit 과정이 종료될 경우 호출되며, 데이터의 emit이 정상적으로 완료 된 후, 처리해야 될 작업이 있다면 onComplete() 내에서 수행할 수 있습니다.

 

✔ Subscription

public interface Subscription {
    public void request(long n);
    public void cancel();
}

[코드 4-3] Subscription 인터페이스

Subscription 인터페이스Subscriber의 구독 자체를 표현한 인터페이스이며, 각 메서드의 역할은 다음과 같습니다.

  • request(long n)
    • Publihser가 emit하는 데이터의 개수를 요청합니다.
  • cancel()
    • 구독을 해지하는 역할을 합니다. 즉, 구독 해지가 발생하면 Publisher는 더이상 데이터를 emit하지 않습니다.

 

✔ Processor

public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {
}

[코드 4-4] Processor 인터페이스

Processor 인터페이스
Subscriber 인터페이스Publisher 인터페이스를 상속받고 있기 때문에

Publisher와 Subscriber의 역할을 동시에 할 수 있는 특징을 가지고 있으며,

별도로 구현해야 되는 추상 메서드는 없습니다.

 

리액티브 스트림즈의 내용만 보아서는 리액티브 프로그래밍의 실체를 알기 어렵습니다.

앞에서 살펴 본 리액티브 스트림즈의 컴포넌트인 Publisher와 Subscriber로 구성된 ‘Hello, Reactive!’ 샘플 코드로 리액티브 프로그래밍의 구조를 조금 더 자세하게 확인할 수 있으니 조금만 기다려주세요!

 

리액티브 스트림즈의 구현체

리액티브 스트림즈가 리액티브 프로그래밍을 위한 사양이니, 분명히 사양에 맞게 구현된 구현체가 존재할 것입니다.

리액티브 스트림즈의 구현체에는 어떤 것들이 있을까요?

 

  • Project Reactor

Project Reactor(줄여서 Reactor)는 리액티브 스트림즈를 구현한 대표적인 구현체로써 Spring과 궁합이 가장 잘 맞는 리액티브 스트림즈 구현체이며, 우리가 다음 유닛에서 학습하게 될 리액티브 스트림즈의 구현체이기도 합니다.

 

Reactor는 Spring 5의 리액티브 스택에 포함되어 있으며 Sprig Reactive Application 구현에 있어 핵심적인 역할을 담당하고 있습니다.

 

  • RxJava

RxJava는 .NET 기반의 리액티브 라이브러리를 넷플릭스에서 Java 언어로 포팅한 JVM 기반의 리액티브 확장 라이브러리입니다.

 

RxJava의 경우 2.0부터 리액티브 스트림즈 표준 사양을 준수하고 있으며,

이 전 버전의 컴포넌트와 함께 혼용되어 사용이 되고 있습니다.

 

  • Java Flow API

Java 역시 Java 9부터 리액티브 스트림즈를 지원하고 있습니다. 그런데 Flow API는 리액티브 스트림즈를 구현한 구현체가 아니라 리액티브 스트림즈 표준 사양을 Java 안에 포함을 시킨 구조라고 볼 수 있습니다.

 

즉, 다양한 벤더들이 JDBC API를 구현한 드라이버를 제공할 수 있도록 SPI(Service Provider Interface) 역할을 하는것 처럼 Flow API 역시 리액티브 스트림즈 사양을 구현한 여러 구현체들에 대한 SPI 역할을 한다고 보면 될 것 같습니다.

 

  • 기타 리액티브 확장(Reactive Extension)

RxJava의 Rx는 Reactive Extension의 줄임말입니다.

 

이 의미는 특정 언어에서 리액티브 스트림즈를 구현한 별도의 구현체가 존재한다는 의미이며, 실제로 다양한 프로그래밍 언어에서 리액티브 스트림즈를 구현한 리액티브 확장(Reactive Extension) 라이브러리를 제공하고 있습니다.

 

대표적인 리액티브 확장(Reactive Extension) 라이브러리로 앞에서 언급한 RxJava가 있으며, 이외에도 RxJS, RxAndroid, RxKotlin, RxPython, RxScala 등이 있습니다.

 


 

핵심 포인트

  • 리액티브 시스템은 클라이언트의 요청에 반응을 잘하는 시스템을 의미한다.
  • 리액티브 프로그래밍은 리액티브 시스템에서 사용되는 프로그래밍 모델이다.
  • 리액티브 스트림즈(Reactive Streams)는 리액티브 프로그래밍을 위한 표준 사양(또는 명세, Specification)이다.
  • 리액티브 스트림즈는 아래의 네 개 컴포넌트로 구성된다.
    • Publisher
    • Subscriber
    • Subscription
    • Processor
  • 다음과 같은 리액티브 스트림즈의 구현체가 사용된다.
    • Project Reactor
    • RxJava
    • Java Flow API
    • 기타 리액티브 확장(Reactive Extension)

 

 

 

 

 

 

 

 

Hello, Reactive로 알아보는 리액티브 프로그래밍 구조

 

 

리액티브 프로그래밍의 대표적인 특징은 바로 선언형 프로그래밍 방식을 사용한다는 것입니다.


따라서 Hello, Reactive 샘플 코드의 구조를 확인하기 전에 먼저 선언형 프로그래밍 방식이 무엇인지 이해할 수 있다면 리액티브 프로그래밍의 코드 구조가 조금 더 친숙하게 느껴질 거라 생각합니다.


명령형 프로그래밍 vs 선언형 프로그래밍

✅ 명령형 프로그래밍


public class ImperativeProgrammingExample {
    public static void main(String[] args){
        // List에 있는 숫자들 중에서 4보다 큰 짝수의 합계 구하기
        List<Integer> numbers = List.of(1, 3, 6, 7, 8, 11);
        int sum = 0;

        for(int number : numbers){
            if(number > 4 && (number % 2 == 0)){
                sum += number;
            }
        }

        System.out.println(sum);
    }
}
[코드 4-5] 명령형 프로그래밍 방식 예

코드 4-5는 여러분이 잘 알고 있는 명령형 프로그래밍 방식의 전형적인 예입니다.


코드를 보면 List에 포함된 숫자들을 for문을 이용해서 순차적으로 접근한 후, if 문으로 특정 조건에 맞는 숫자들만 sum 변수에 더해서 합계를 구하고 있습니다.


명령형 프로그래밍 방식의 경우, 코드가 어떤식으로 실행되어야 하는지에 대한 구체적인 로직들이 코드 안에 그대로 들어납니다.


✅ 선언형 프로그래밍


public class DeclarativeProgramingExample {
    public static void main(String[] args){
        // List에 있는 숫자들 중에서 4보다 큰 짝수의 합계 구하기
        List<Integer> numbers = List.of(1, 3, 6, 7, 8, 11);

        int sum =
                numbers.stream()
                        .filter(number -> number > 4 && (number % 2 == 0))
                        .mapToInt(number -> number)
                        .sum();

        System.out.println("# 선언형 프로그래밍: " + sum);
    }
}
[코드 4-6] 선언형 프로그래밍 방식 예

코드 4-6은 선언형 프로그래밍 방식의 코드 예입니다.


Java에서 선언형 프로그래밍 방식을 이해하기 위한 가장 적절한 예는 바로 Java 8부터 지원하는 Stream API입니다.


코드 4-6 역시 List에 포함된 숫자들을 처리하는 것은 코드 4-5와 동일하지만 처리 방식은 코드 4-5와 전혀 다릅니다.


Java Stream API를 사용하기 때문에 코드 상에 보이지 않는 내부 반복자가 명령형 프로그래밍 방식에서 사용하는 for문을 대체하고 있습니다.

또한 filter() 메서드(Operation)가 if 문을 대신해서 조건에 만족하는 숫자를 필터링하고 있습니다.


그런데 Stream API를 사용하는 것이 왜 선언형 프로그래밍 방식이냐고 의문을 가지는 분들이 있을거라 생각합니다.


명령형 프로그래밍 방식으로 작성된 코드 4-5는 코드가 위에서 아래로 순차적으로 실행이 됩니다.

즉, for문을 만나게 되면 for문 내부로 진입하게 되고, 이어서 if문을 만나면 if 문의 조건을 판단한 후에 조건에 맞으면 sum 변수에 숫자를 더한 뒤에 다시 for 문을 반복합니다.


그런데 Stream API를 사용한 코드 4-6은 numbers.stream().filter().mpaToInt().sum()과 같은 메서드 체인이 순차적으로 실행이 되는 것이 아닙니다.

filter()나 mapToInt() 메서드에 파라미터를 전달하기 때문에 즉시 호출되는 것처럼 생각될 수 있지만 그렇지 않습니다.

여러분이 Java 유닛에서 Stream에 대해 학습한 내용을 떠올려 본다면 왜 즉시 호출되는게 아닌지 이미 알고 있을거라 생각합니다.


Stream의 경우 최종 연산을 수행하는 메서드를 호출하지 않으면 앞에서 작성한 메서드 체인들이 실행 되지 않는다는 사실, 기억날까요? ^^


다시 말해 Stream의 메서드 체인(중간 연산)에는 이러 이러한 작업을 해 달라고 선언(요청)하는 람다 표현식만 넘겨주고,

최종 연산이 호출될 때 비로소 전달 받은 람다 표현식을 기반으로 동작을 수행합니다.


따라서 선언형 프로그래밍 방식은 하나부터 열까지 개발자가 일일이 로직을 모두 작성하지 않습니다.

대신에 정말 필요한 동작들을 람다 표현식으로 정의(선언)하고

구체적인 동작 수행은 Operation(연산) 메서드 체인에 위임합니다.

 
 
 

Hello, Reactive 샘플 코드로 보는 리액티브 프로그래밍의 구조

명령형 프로그래밍 방식과 선언형 프로그래밍 방식의 차이점을 이해했다면 리액티브 프로그래밍의 기본 구조를 조금 더 쉽게 이해할 수 있을거라 생각합니다. ^^


Hello, Reactive 샘플 코드를 통해 리액티브 프로그래밍의 기본 구조를 이해해 봅시다.


package com.codestates.example;

import reactor.core.publisher.Mono;

// 리액티브 프로그래밍 기본 구조
public class HelloReactiveExample01 {
    public static void main(String[] args) {
        // (1) Publisher의 역할
        Mono<String> mono = Mono.just("Hello, Reactive");

        // (2) Subscriber의 역할
        mono.subscribe(message -> System.out.println(message));
    }
}
[코드 4-7] 리액티브 프로그래밍 기본 구조

코드 4-7은 새로운 프로그래밍 언어를 배울 때 가장 기본이 되는 “Hello World”를 콘솔에 출력하는 프로그램입니다.

우리는 뒤에서 학습하게 될 리액티브 스트림즈의 구현체인 Reactor를 통해 “Hello, Reactive”를 출력하고 있습니다. ^^


여러분들이 이 전 챕터에서 학습한 리액티브 스트림즈의 컴포넌트 중에서 Publisher와 Subscriber를 떠올려 보세요.


Publisher는 데이터를 emit하는 역할을 하며, Subsciber는 Publisher가 emit한 데이터를 전달 받아서 소비하는 역할을 한다고 했습니다.


코드 4-7에서 Puhlisher의 역할을 하는 것이 바로 Mono입니다.

그리고 Subscriber의 역할을 하는 것이 바로 subscribe() 메서드 내부에 정의된 람다 표현식인 message -> System.out.println(message) 입니다.


Reactor에 대해서는 이어지는 유닛에서 학습하게 되므로 구체적인 사용법은 지금 당장은 몰라도 됩니다. ^^


코드 4-7은 여러분들의 이해를 돕기 위해 코드를 부분적으로 나누었지만 Java의 Stream에서 메서드 체인 형태로 사용할 수 있는것 처럼 리액티브 프로그래밍 역시 메서드 체인을 구성할 수 있습니다.


package com.codestates.example;

import reactor.core.publisher.Mono;

// 리액티브 프로그래밍 기본 구조
public class HelloReactiveExample02 {
    public static void main(String[] args) {
        Mono
            .just("Hello, Reactive")
            .subscribe(message -> System.out.println(message));
    }
}
[코드 4-8] 리액티브 프로그래밍 기본 구조 예 2

코드 4-8은 코드 4-7의 코드를 하나의 메서드 체인 형태로 표현한 것입니다.

이렇게 보니 Java의 Stream AP의 메서드 체인과 비슷하다는 생각이 들지 않나요? ^^

리액티브 프로그래밍 역시 선언형 프로그래밍 방식으로 구성이 되기 때문입니다.


그런데 Java의 Stream API리액티브 프로그래밍선언형 프로그래밍 방식으로 구성되는 공통점이 존재하지만 둘 사이에는 차이점이 더 많이 존재하며 용도 역시 확연히 다릅니다.


리액티브 프로그래밍에서 사용되는 용어 정의

리액티브 프로그래밍에는 여러분들이 처음 들어보는 생소한 용어들을 꽤 많이 볼 수 있습니다.

용어 자체의 생소함 때문에 리액티브 프로그래밍을 학습하는데 어려움을 겪는 경우 역시 흔한일입니다.


여러분들이 이런 어려움을 조금이라도 덜 겪기 위해 리액티브 프로그래밍에서 사용되는 용어를 간단히 정리해 보도록 하겠습니다. ^^


package com.codestates.example;

import reactor.core.publisher.Flux;

import java.util.List;

public class ReactiveGlossaryExample {
    public static void main(String[] args) {
        Flux
            .fromIterable(List.of(1, 3, 6, 7, 8, 11))
            .filter(number -> number > 4 && (number % 2 == 0))
            .reduce((n1, n2) -> n1 + n2)
            .subscribe(System.out::println);

    }
}
[코드 4-9] 리액티브 프로그래밍 기본 구조 3

코드 4-9는 리액티브 프로그래밍에서 사용되는 용어를 이해하기 위한 예제 코드입니다.

코드 4-9의 의 일부 코드들을 이용해서 리액티브 프로그래밍에서 사용되는 용어를 이해해 보도록 합시다.


다시 말하지만 이어지는 Project Reactor 유닛에서 학습할 예정이니 코드 4-9에서 사용된 코드들의 사용법을 지금 몰라도 됩니다.

용어를 이해하는 차원에서 가볍게 봐주길 바래봅니다.

참고로 코드 4-9의 실행 결과는 코드 4-6의 선언형 프로그래밍 방식 예제 코드의 실행 결과와 동일합니다.


  • Publisher

리액티브 스트림즈 사양에서도 확인한 것 처럼 Publisher는 데이터를 내보내는 주체를 의미합니다.

코드 4-9에서는 Flux가 Publisher입니다.


  • Emit

Publisher가 데이터를 내보내는 것을 Emit 이라고 합니다. 굳이 우리말로 표현하자면 통지, 발행, 방출 정도로 표현할 수 있지만 Emit이라는 용어 그대로를 이해하고 있는 것이 좋습니다.


  • Subscriber

Subscriber는 Publisher가 emit한 데이터를 전달 받아서 소비하는 주체를 의미합니다.

코드 4-9에서는 subscribe(System.out::println) 중에서 System.out::printlnSubscriber에 해당 됩니다. 람다 표현식을 메서드 레퍼런스로 축약하지 않았다면 람다 표현식 자체가 Subscriber에 해당됩니다.


  • Subscribe

Subscribe는 구독을 의미합니다.

코드 4-9와 같이 subscribe() 메서드를 호출하면 구독을 하는 것입니다.


  • Signal

리액티브 프로그래밍 관련 문서를 보다보면 Signal이라는 용어를 굉장히 많이 볼 수 있습니다.

SignalPublisher가 발생시키는 이벤트를 의미합니다.

예를 들어서 코드 4-9에서 subscribe() 메서드가 호출되면 Publisher인 Flux는 숫자 데이터를 하나씩 하나씩 emit 합니다.

이때 숫자 데이터를 하나씩 emit하는 자체를 리액티브 프로그래밍에서는 이벤트가 발생하는 것으로 간주하며, 이 이벤트 발생을 다른 컴포넌트에게 전달하는 것을 Signal을 전송한다라고 표현합니다.


  • Operator

Operator는 리액티브 프로그래밍에서 어떤 동작을 수행하는 메서드를 의미합니다.

코드 4-9에서 fromIterable(), filter(), reduce() 등 메서드 하나 하나를 Operator라고 합니다.

우리말로 연산자라는 표현을 사용하지만 우리 코스에서는 영어 표현 그대로 Operator라는 영문 표현 그대로를 사용합니다.


  • Sequence

Sequence는 Operator 체인으로 표현되는 데이터의 흐름을 의미합니다. 코드 4-9에서 Operator 체인으로 작성된 코드 자체하나의 Sequence라고 이해하면 됩니다.


  • Upstream / Downstream

Sequence 상의 특정 Operator를 기준으로

위쪽의 Sequence 일부를 Upstream이라고 하며,

아래 쪽 Sequence 일부를 Downstream이라고 표현합니다.

 

코드 4-9에서 filter() Operaotr를 기준에서 보면 filter() Operator 위 쪽의 fromIterable()은 Upstream이 됩니다.

그리고 filter() Operator 아래 쪽의 reduce() Operator는 Downstream이 됩니다.




핵심 포인트

  • 선언형 프로그래밍 방식은 실행할 코드를 선언만 하며, 순차적으로 실행되지 않는다.
  • 실행 로직을 작성한 코드대로 실행이 되는 명령형 프로그래밍 방식과 달리 선언형 프로그래밍 방식은 실행 로직의 일부만 람다 표현식으로 전달하며 전달 받은 람다 표현식을 기반으로 Operation 메서드 내부에서 전체 로직을 실행한다.
  • 리액티브 프로그래밍에서 사용되는 용어 정의
    • Publisher
      • Publisher는 데이터를 내보내는 주체를 의미한다.
    • Emit
      • Publisher가 데이터를 내보내는 것을 Emit 이라고 한다.
    • Subscriber
      • Subscriber는 Publisher가 emit한 데이터를 전달 받아서 소비하는 주체를 의미한다.
    • Subscribe
      • Subscribe는 구독을 의미한다.
    • Signal
      • Signal은 Publisher가 발생시키는 이벤트를 의미한다. \
    • Operator
      • Operator는 리액티브 프로그래밍에서 어떤 동작을 수행하는 메서드를 의미한다.
    • Sequence
      • Sequence는 Operator 체인으로 표현되는 데이터의 흐름을 의미한다.
    • Upstream / Downstream
      • Sequence 상의 특정 Operator를 기준으로 위쪽의 Sequence 일부를 Upstream이라고 하며, 아래 쪽 Sequence 일부를 Downstream이라고 표현한다.