https://book.naver.com/bookdb/book_detail.naver?bid=20551523
스프링 부트 실전 활용 마스터
간단한 장바구니 예제를 리액터를 활용한 논블로킹/비동기 방식으로 구현하며 비밀을 파헤쳐본다. 스프링 헤이티오스를 적용해서 변경 여파를 최소화하면서 진화하는 API를 만들어보고, 스프링
www.aladin.co.kr
이 글은 스프링 부트 실전 활용 마스터를 읽고 희미한 기억을 또렷한 기록으로 바꾸기 위해 작성했습니다
해당 책으로 통해 처음으로 스프링 리액티브 프로그래밍을 접하게 되었습니다
그래서 리액티브 프로그래밍이 탄생한 배경과 왜 스프링 웹플럭스가 등장하게 되었는지
먼저 알아보겠습니다
리액티브 프로그래밍의 서막
"2017년 9월 스프링 프레임워크 5.0에 새로운 패러다임 리액티브 프로그래밍이 추가되었다!!"
리액티브 프로그래밍
리액티브 프로그래밍을 이해하기 위해서는 아래 글을 읽는 것이 좋습니다!!
https://spring.io/blog/2016/06/07/notes-on-reactive-programming-part-i-the-reactive-landscape
Notes on Reactive Programming Part I: The Reactive Landscape
<div class="paragraph"> <p>Reactive Programming is interesting (again) and there is a lot of noise about it at the moment, not all of which is very easy to understand for an outsider and simple enterprise Java developer, such as the author. This article (t
spring.io
[번역] 리액티브 프로그래밍이란?
원문: https://medium.com/reactive-programming/what-is-reactive-programming-bc9fa7f4a7fc#.y4pkewket 프로그래밍 패러다임 관점에서나 탄생 이유의 관점에서나 리액티브(Reactive)를 이해하기 위해서는 현재..
blog.canapio.com
리액티브 프로그래밍은 1970년에 학술자료로 나왔지만 각광을 받지 못했습니다.
하지만 2015년부터 관심이 급격히 증가하게 되었습니다
왜 각광을 받게 되었을까요?
2005년 페이스북은 550만 유저를 가지고 있다가
2014년에는 13억 유저를 보유하게 되었고 트래픽이 10년 전에 비해 확 늘게 되었습니다
그러다 보니 소프트웨어가 중요해지면서 사용자에게 24시간 동안 끊임없이 콘텐츠를 제공해야 했습니다.
이에따라 확장과 예측에 관한 이슈가 중요해지면서 과거의 패러다임이 현재까지 이어질 수는 없었던 것이었습니다.
이런 시스템은 비동기적으로 인입되는 데이터 스트림을 논블로킹 방식으로 처리할 수 있어야 합니다
그러다보니 개발자들은 기존 자원을 더 효율적이고 일관성 있게 사용하는 방법을 찾고 있으며
그 해법이 바로 리액트 스트림입니다.
프로젝트 리액터는 VM웨어에서 만든 리액티브 스트림 구현체로
리액터를 사용하면 리액티브 프로그래밍의 특성을 활용할 수 있게 됩니다
프로젝트 리액터의 풍부한 프로그래밍 모델
- 함수형 프로그래밍에서 수행하는 변환
- onNext(), onError(), onComplete()시그널 처럼
Future객체에는 없는 리액티브 스트림 수명주기에 연결
리액티브 프로그래밍 특성
- 논블로킹, 비동기 프로그래밍 모델
- 함수형 프로그래밍 스타일
- 스레드를 신경 쓸 필요 없는 동시성
리액티브 스트림
발행자와 구독자 사이의 간단한 계약을 정의하는 명세
스프링 웹플럭스의 등장
https://www.jrebel.com/blog/java-web-frameworks-index
Java Web Frameworks Index | JRebel by Perforce
Read our article to see ranked Java web frameworks using data from Stack Overflow, LinkedIn, GitHub, and Google to find the best Java MVC framework for you.
www.jrebel.com
위의 글에 따르면, 웹 애플리케이션을 만들 때 가장 널리 사용한 도구는 스프링 MVC라고 합니다
하지만 스프링 프레임워크 5.0에서 새로운 패러다임 리액티브 프로그래밍이 추가되었고
웹 애플리케이션에서 리액티브 프로그래밍을 제공하는 스프링 웹플럭스가 등장하게 됩니다
그러다 보니 확장 요구가 커질수록 스프링 웹플럭스를 활용해서 웹 요청을 리액티브하게 처리해야 했습니다
스프링 MVC도 자바 서블릿 API 기반으로, 서블릿 3.1~ 비동기 방식을 일부 지원했으나
리액티브 이벤트와 배압 시그널을 지원하지 않았습니다.
배압
구독자가 스스로 처리할 수 있을 만큼의 데이터만을 발행자에게 요청해서 데이터 전송량을 조절할 수 있는 메커니즘
(프로젝트 리액터에서는 흐름과 핸들러를 정의할 수 있지만 구독하기 전까지는 아무런 반응이 없다)
리액티브 이벤트 루프 [참고]
계속 요청 핸들러로부터 푸시된 이벤트를 감지하기에 하나의 스레드로 많은 요청을 병렬로 처리한다.
스프링 웹플럭스와 네티 조합
네티(Netty)는 프로토콜 서버, 클라이언트 등 자바 네트워크 애플리케이션을 개발하기 위한 프레임워크입니다.
또한, 100% 논블로킹, 비동기 웹 컨테이너로 서블릿 스펙에 구속이 되지 않습니다
그러므로 스프링 웹플럭스 + 네티를 사용하게 되면 프로그래밍 모델 그대로 작성한 코드를
서블릿 컨테이너가 아닌 네티 위에서 실행할 수 있게 됩니다
간단한 주방 서비스 만들기
시간 관계상 스프링 부트 프로젝트 생성은 생략하겠습니다 🫠
아래의 dependency를 추가해줍니다
- Spring Reactive Web : 스프링 웹플럭스 + 내장형 네티
- Lombok : 어노테이션 기반으로 코드를 자동완성해주는 라이브러리
리액티브 웹 컨테이너는 프로젝트 리액터에 맞도록 네티를 감싸서 만든 리액터 네티입니다
도메인 객체 정의
public class Dish {
private String description;
private boolean delivered = false;
public Dish(String description) {
this.description = description;
}
public static Dish deliver(Dish dish) {
Dish deliveredDish = new Dish(dish.description);
deliveredDish.delivered = true;
return deliveredDish;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public boolean isDelivered() {
return delivered;
}
@Override
public String toString() {
return "Dish{" +
"description='" + description + '\'' +
", delivered=" + delivered +
'}';
}
}
주방 서비스
@Service
public class KitchenService {
/**
* 메뉴
*/
private List<Dish> menu = Arrays.asList(
new Dish("뉴욕 피자"),
new Dish("시카고 피자"),
new Dish("고르곤졸라 피자"),
new Dish("파인애플 피자")
);
/**
* 요리 스트럼 생성
* @return
*/
public Flux<Dish> getDishes() {
return Flux.<Dish> generate(sink -> sink.next(ranDomDish())).delayElements(Duration.ofMillis(250));
}
/**
* 요리 무작위 선택
* @return
*/
private Dish ranDomDish() {
return menu.get(new Random().nextInt(menu.size()));
}
}
Flux
리액티브 스트림은 수요 조절에 기반하고 있는데,
프로젝트 리액터는 핵심 타입인 Flux<T>를 사용해서 수요 조절을 구현합니다
Flux<T>는 일련의 T객체를 담고 있는 컨테이너입니다
소스 보기!
Flux.<Dish> generate(sink -> sink.next(ranDomDish())).delayElements(Duration.ofMillis(250));
주방에서는 0.25초마다 메뉴에 있는 요리 중 무작위로 하나를 제공해준다
randomDish()를 사용해서 무작위 요리를 가져왔고
sink은 Flux에 포함될 원소를 동적으로 발행해준다
위의 소스에는 없지만 이 책의 저자는 Flux.map() 함수는 계속 사용되므로 이해하라고 나와있습니다
Flux.map()
public final <V> Flux<V> map(Function<? super T, ? extends V> mapper) {
if (this instanceof Fuseable) {
return onAssembly(new FluxMapFuseable<>(this, mapper));
}
return onAssembly(new FluxMap<>(this, mapper));
}
각 아이템에 동기 함수를 적용하여 이 Flux에서 방출되는 아이템을 변환하다 [참고]
Flux.generate
public static <T> Flux<T> generate(Consumer<SynchronousSink<T>> generator) {
Objects.requireNonNull(generator, "generator");
return onAssembly(new FluxGenerate<>(generator));
}
소비자 콜백을 통해 신호를 발생시켜 Flux 생성
파라미터 타입은 Consumer<SynchronousSink<T>인데 sink는 여기에서 따온 이름입니다
마지막으로 Flux에는 다음과 같은 특징이 있습니다
- 하나 이상의 Dish 포함 가능
- 각 Dish가 제공될 때 어떤 일이 발생하는지 지정 가능
- 성공과 실패의 두 가지 경로 모두에 대한 처리 방향 정의 가능
- 결과 폴링 불필요
- 함수형 프로그래밍 지원
컨트롤러
@RestController
@RequiredArgsConstructor
public class ServerController {
private final KitchenService kitchenService;
@GetMapping(value = "/server", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
Flux<Dish> serveDishes() {
return kitchenService.getDishes();
}
}
반환되는 미디어 타입은 text/event-stream이라 클라이언트는 서버가 반환하는 스트림을 쉽게 소비할 수 있습니다
컨트롤러 메소드에서 리액터 타입을 반환하도록 작성하면 스프링 웹플럭스가 적절한 옵션과 함께 적절한 타이밍에 구독합니다
Flux<Dish>는 다수의 요리를 반환해주는 타입입니다
자바 Collection과 가장 큰 차이점은 요리가 비동기적으로 전달된다는 점!
비동기 방식 전달은 리액티브 실행 환경인 리액터와 네티에서 담당합니다
실행해보기!
서버를 실행하고~!
명령행 도구에서 아래와 같이 입력하면~!
curl -N -v localhost:8080/server
피자~! 🍕 배고프다!!
'책 > 기록' 카테고리의 다른 글
[데일카네기 인간관계론] 사람을 다루는 기본 방법 3가지 (0) | 2023.01.16 |
---|---|
조종사의 비행 계측기에 해당하는 장치를 만들자 (0) | 2022.10.13 |
[Effective Java] 아이템5 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2022.06.21 |
[Effective Java] 아이템4 인스턴스화를 막으려거든 private 생성자를 사용하라 (0) | 2022.06.20 |
[Effective Java] 아이템3 private 생성자나 열거 타입으로 싱글턴임을 보증하라 (0) | 2022.06.20 |