web/Spring

Spring Reactive Web Application

반응형

Sprint 5에서 리액티브 프로그래밍을 지원하는 웹 애플리케이션을 만들 수 있다.

리액티브 프로그램이란?
이전시간에 정리했었지만 스프링 리액티브 프로그래밍을 들어가기 전에 간단하게 정리해 보자. 일반적으로 리액티브 프로그래밍은 비동기, evnet-driven 방식으로 non-blocking 하는 프로그래밍으로써 일반적인 시스템 보다 작은 작은 쓰레드 수가 필요하다.

그럼 왜?
비동기-논블록킹 리액티브 개발이 가능. 기존 멀티쓰레드 블로킹 방식과는 다르게 서버의 응답에 의지하지 않는 효율적 개발이 가능. 서버간에 호출이 잦은 마이크로 서비스에서 사용됨

Spring Web Reactive Module (Servlet 3.1 이상부터 지원)
Spring Framework 5는 spring-web-reactive module을 포함한다. 이 module은 REST, HTML browser 그리고 웹 소켓에서 상호작용을 할 수 있도록 reactive HTTP와 Web Socket을 지원한다.


Annotation-based 프로그래밍 모델
기존 Spring MVC와 동일하게 @Controller를 사용이 가능하다. 주요한 차이점은 HandlerMapping과 HandlerAdapter등의 내용이 비동기인지 차이이고 리액티브에서는 HttpServletRequest, HttpServletResponse 보다 ServerHttpRequest, ServerHttpResponse에서 동작한다.

exeample)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@RestController
public class PersonController {
 
    private final PersonRepository repository;
 
    public PersonController(PersonRepository repository) {
        this.repository = repository;
    }
 
    @PostMapping("/person")
    Mono<Void> create(@RequestBody Publisher<Person> personStream) {
        return this.repository.save(personStream).then();
    }
 
    @GetMapping("/person")
    Flux<Person> list() {
        return this.repository.findAll();
    }
 
    @GetMapping("/person/{id}")
    Mono<Person> findById(@PathVariable String id) {
        return this.repository.findOne(id);
    }
}
cs


함수형 프로그래밍 모델
함수형 프로그래밍 모델을 사용하여 routing과 request를 handling 할 수있다. 가장 주요로 사용하는 함수형 인터페이스는 RouterFunction과 HandlerFunction이다. 이 둘을 사용하면 웹 애플리케이션에서 손쉽게 block을 생성할 수 있다.

아래 예는 person에 대한 데이터를 router로 request handling 하는 것을 보여준다.
- endpoint, accept type, response 등등

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 
/**
 * reactive
 *
 * @author wedul
 * @since 2019-01-12
 **/
@Configuration
@EnableWebFlux
public class PersonRouterFunction implements WebFluxConfigurer {
 
  @Bean
  public RouterFunction<ServerResponse> routes(FunctionHandler handler) {
    return RouterFunctions.route(GET("/person"), handler::functionHandler);
  }
 
}
 
@Component
class FunctionHandler {
  public Mono<ServerResponse> functionHandler(ServerRequest req) {
    Mono<Person> person = Mono.just(new Person("wedul"));
    return ServerResponse.ok().body(person, Person.class);
  }
}
cs


여기서 route에서 받는 파라미터는 RouterFuction 인터페이스로써 Mono<HandlerFunction<T>> route(ServerRequest request) 함수를 정의해서 전달해야한다. 그래서 route에 미리 정의해놓은 fuctionHandler를 전달한다. 이렇게 정의해서 사용하는 Handler를 route에 무조건 적용한다면 복잡해지고 다른곳에서 공통으로 사용할 수 없으니 위에 처럼 따로 구분해서 사용할 것.

MVC annotation으로만 사용하던 나에게는 불편해보이지만 함수형 프로그램을 할 수 있다는 장점이 있는거 같다.


웹 클라이언트
선언된 컨트롤러에서 Flux 또는 Mono를 읽고 구독을 진행해서 데이터를 읽는다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
 * reactive
 *
 * @author wedul
 * @since 2019-01-12
 **/
public class PersonClient {
 
  WebClient client = WebClient.create("https://wedul.pos:8080");
 
  public void Test() {
    Flux<Person> personMono = client.get().uri("/person").retrieve().bodyToFlux(Person.class);
 
    personMono.subscribe(System.out::println);
  }
 
}
cs


예제 github

https://github.com/weduls/reactive

반응형