Spring Boot WebFlux를 사용해 리액티브 스프링을 사용할 것입니다. maven으로 빌드를 해야 해서 골치가 조금 아픕니다. (^..^)
리액티브 스트림이란?
발행자(publisher)와 구독자(subscriber) 사이의 간단한 계약을 정의하는 명세다. 트래픽을 가능한 한 빨리 발행하는 대신에 구독자가 '난 10개만 더 받을 수 있어.'라고 발행자에게 알리는 방식으로 트래픽을 제어할 수 있다.
리액터란?
리액티브 스트림은 수요 조절에 기반하고 있다. 프로젝트 리액터는 핵심 타입인 Flux<T>를 사용해 수요 조절을 구현한다. Flux<T>는 일련의 T 객체를 담고 있는 컨테이너다.
예시를 들자면 레스토랑에서 서빙 점원과 비슷하다고 할 수 있다. 주방에서 요리가 완성되면, 점원이 요리를 받아서 손님에게 가져다 주고, 다시 제자리로 돌아와서 다음 요리를 기다린다. 점원은 요리가 언제 완성될지 모른다.
점원(Reactor)은 언제가 됐든 요리 완성에 대한 반응-행동(React)한다.
코드
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
pom.xml 에 <dependencies> 태그 하위에 webflux 의존성을 추가한다.
도메인
public class Dish {
private String description;
private boolean delivered = false;
public static Dish deliver(Dish dish){
Dish deliveredDish= new Dish(dish.description);
deliveredDish.delivered= true;
return deliveredDish;
}
public Dish(String description) {
this.description = description;
}
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 +
'}';
}
}
간단히 개념을 확인하기 위한 하드코딩된 도메인이다.
컨트롤러
@RestController // 1
public class ServerController {
private final KitchenService kitchen;
public ServerController(KitchenService kitchen){
this.kitchen=kitchen;
}
@GetMapping(value="/server", produces = MediaType.TEXT_EVENT_STREAM_VALUE) // 2
Flux<Dish> serveDishes(){
return this.kitchen.getDishes();
}
}
- 결과 데이터를 직렬화하고 HTTP 응답 본문에 직접 써서 반환하는 REST 컨트롤러임을 나타낸다.
- 반환되는 미디어 타입은 'text/event-stream'이고, 클라이언트는 서버가 반환하는 스트림을 쉽게 소비할 수 있다. (미디어타입을 지정하지 않으면 스트림을 소비하지 못한다.)
서비스
@Service
public class KitchenService {
private List<Dish> menu = Arrays.asList(new Dish("Sesame chicken"),
new Dish("Lo mein noodles"),
new Dish("Sweet & sour beef"));
private Random picker = new Random();
Flux<Dish> getDishes(){
return Flux.<Dish> generate(sink -> sink.next(randomDish()))
.delayElements(Duration.ofMillis(250));
}
private Dish randomDish() {
return menu.get(picker.nextInt(menu.size()));
}
}
Flux.generate()를 사용해서 요리를 연속적으로 계속 만들어 제공한다. 요리 제공 속도를 조절하기 위해 delayElements(Duration.ofMillis(250))을 사용해 250 밀리초마다 하나의 요리를 제공한다.
MVC 모델과 크게 다른 점은 없으나 Flux<?> 리액터 타입으로 반환하는 점이 차이가 난다.
실행 결과
웹을 이용해서 '/server'에 GET 요청을 보낸 후 응답이다. 250미리초 간격으로 data가 생성되는 것을 볼 수 있다.
'/serve-dishes' GET 요청은 Flux<Dish> 결과를 스트림 방식으로 반환하는 것은 동일하지만 dish를 deliver() 매핑함수를 사용해 매핑 후 반환한다는 점이 다르다. delivered 값이 true로 설정된 새로운 요리를 만들어 낸다.
CLI로 도구를 사용해서도 요청할 수 있다.
curl -N -v localhost:8080/server
'Develop > Spring˙Spring Boot' 카테고리의 다른 글
[Spring Reactive] 리액티브 데이터 Repository 정의하기 (0) | 2023.03.12 |
---|---|
[Spring Reactive] 리액티브 데이터베이스 저장 요건 (0) | 2023.03.10 |
[Spring] 컴포넌트 탐색, 의존관계 주입과 서비스 로케이터 (0) | 2023.03.07 |
[Spring Boot] 애플리케이션 배포하기 (0) | 2023.02.18 |
[Spring Boot] 액추에이터로 내부 들여다보기 - 2 (0) | 2023.02.17 |