[TIL] Spring WebFlux Reactive 프로그래밍
코드스테이츠 백엔드 부트캠프 D+102
오늘은 리액티브 프로그래밍에 대해 공부해보는 날이다.
아마 깊은 내용은 다루지 않고, 간단한 지식들만 공부 할 것 같다.
우리는 Spring MVC 기반의 애플리케이션을 사용하고있는데
최신 기술로 Spring Reactive가 나와서 후에 어떻게
바뀔지는 아무도 모르니 Spring MVC 이해를 마친 후
해당 기술에 대해 깊게 공부해볼 필요가 있을 것 같다.
리액티브 프로그래밍이란?
기존의 명령형 프로그래밍 방식과 달리 선언형 프로그래밍 방식을 사용한다.
클라이언트의 요청에 반응을 잘하는 시스템을 의미한다.
리액티브 시스템 관점에서의 반응은 쓰레드의 Non-Blocking과 관련이 있다.
클라이언트의 요청에 대한 대기 시간을 최소화 할 수 있도록
요청 쓰레드가 차단되지 않게 함으로써, 클라이언트에게 즉각적으로
반응하도록 구성된 시스템이라고 볼 수 있다.
리액티브 시스템의 특징을 알아보자
1). MEANS
-. 리액티브 시스템에서 사용하는 커뮤니케이션 수단
- Message Driven
-. 리액티브 시스템에서는 메세지 기반 통신을 통해 여러 시스템 간에 느슨한 결합을 유지한다.
2). FORM
-. 메세지 기반 통신을 통해 리액티브 시스템이 어떤 특성을 가지는 구조로 형성되는지를 의미
- Elastic
-. 시스템으로 들어오는 요청량이 적거나 많거나에 상관없이 일정한 응답성을 유지하는 것 - Resillient
-. 시스템의 일부분에 장애가 발생하더라도 응답성을 유지하는 것
3). VALUE
-. 리액티브 시스템의 핵심 가치가 무엇인지를 표현하는 영역
- Responsive
-. 리액티브 시스템은 클라이언트의 요청에 즉각적으로 응답할 수 있어야함을 의미 - Maintainable
-. 클라이언트의 요청에 대한 즉각적인 응답이 지속가능해야함을 의미 - Extensible
-. 클라이언트의 요청에 대한 처리량을 자동으로 확장하고 축소할 수 있어야함을 의미
리액티브 스트림즈란?
리액티브 프로그래밍을 위한 표준사양이다.
리액티브 스트림즈에서 사양으로 정의된 구성요소를 알아보자
1). Publisher 인터페이스
public interface Publisher<T> {
public void subscribe(Subscriber<? super T> s);
}
-. 데이터 소스로 부터 데이터를 내보내는(emit) 역할을 한다.
-. subscribe();
추상 메서드를 포함하고 있고, 매개변수로 전달되는 Subscriberrk
Publisher로부터 내보내진 데이터를 소비하는 역할을 한다.
2). Subscriber 인터페이스
public interface Subscriber<T> {
public void onSubscribe(Subscription s);
public void onNext(T t);
public void onError(Throwable t);
public void onComplete();
}
-. Publisher로 부터 내보내진 데이터를 소비하는 역할을 한다.
-. onSubscribe(Subscription s);
- 구독이 시작되는 시점에 호출됨.
- Pusblisher에게 요청할 데이터의 개수를 지정하거나 구독해지 처리가 가능
-. onNext(T t)
- Publisher가 데이터를 emit할 때 호출됨
- emti된 데이터를 전달 받아서 소비할 수 있다.
-. onError(Throwable t)
- Publisher로부터 emit된 데이터가 Subscriber에게 전달되는 과정에서
에러가 발생할 경우에 호출된다.
-. onComplete()
- Publisher가 데이터를 emit하는 과정이 종료될 경우 호출됨
- emit이 정상적으로 완료된 후, 처리해야 될 작업이 있다면 해당 메서드 내에서 수행할 수 있다.
3). Subscription 인터페이스
public interface Subscription {
public void request(long n);
public void cancel();
}
-. Subscriber의 구독 자체를 표현한 인터페이스이다.
-. request(long n)
- Publisher가 emit하는 데이터의 개수를 요청
-. cancel()
- 구독을 해지하는 역할을한다. 구독해지가 발생하면 Publisher는 더이상 데이터를 Emit하지 않는다.
4). Processor 인터페이스
public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {
}
-. 별도로 구현해야 되는 추상메서드는 없다.
-. Publisher와 Subscriber의 역할을 동시에 할 수 있는 특징을 가지고 있다.
5). 구현체들
- Project Reactor
- RxJava
- Java Flow API
코드로 알아보기
public class ReactiveExample {
public static void main(String[] args) {
// Publisher의 역할
Mono<String> mono = Mono.just("Hello, Reactive");
// Subscriber의 역할
mono.subscribe(message -> System.out.println(message));
}
}
// 출력
Hello, Reactive
리액티브 스트림즈 구현체인 Project Reactor을 통해 출력하고 있는 모습이다.
Mono
의 역할이 Publisher의 역할이고
Subscriber는 Publisher가 emit한 데이터를 전달 받아서
소비하는 역할이라고 위에서 공부했었다.
Subscriber 역할을 하는 것은 mono.subscribe();
메서드이고
내부에 정의된 람다 표현식을 사용하고 있다.
기존에 우리가 사용했던 Stream과 동일하게 메서드 체인형식으로 구성도 가능하다.
public class ReactiveExample {
public static void main(String[] args) {
Mono
.just("Hello, Reactive")
.subscribe(message -> System.out.println(message));
}
}
// 출력
Hello, Reactive
다른 형식의 예제를 알아보자
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);
}
}
// 출력
14
Publisher -> Flux
가 Pusblisher 이다.
Emit -> Flux
가 데이터를 내보내는 것을 가르킴
Subscriber -> Flux
가 emit한 데이터를 전달 받아서 소비하는 주체
즉, System.out::println
부분이 Subscriber에 해당한다.
Subscribe -> subscribe
메서드를 호출하면 구독을 하는 것이다.
Signal -> Publisher가 발생시키는 이벤트를 의미한다.
Operator -> 어떤 동작을 수행하는 메서드를 의미한다.
fromIterable()
, filter()
, reduce()
등 하나하나들 Operator이라 한다.
Sequence -> Operator 체인으로 표현되는 데이터의 흐름을 의미한다.
해당 코드에선 코드자체를 하나의 Sequence라고 보면된다.
Upstream -> Operator 기준으로 위쪽 Sequence 일부를 Upstream이라함
Downstream -> Operator 기준으로 아래쪽 Sequence 일부를 Downstream이라함
오늘의 커피량: ☕️ ☕️
오늘의 점심: 제육볶음, 김치찌개, 밥