스프링의 변천사 그리고 Java 9 과 Spring 5 (3)

3. 새로운 변화

새로운 위기 : 애노테이션과 메타프로그래밍 관례의 범람.
애노테이션은 컴파일러에 검증되지 않고 코드 행위를 규정하지 않는다.
규칙이나 표준이 없어 이해하기 어렵고 오해하기 쉽다. 그리고 테스트가 안된다.

@Controller
@RequestMaping("/path")
public class MyController extends SuperController implements MyInterface {
  // home() 은 어떤 url 에 매핑되나?
  @RequestMapping("/home")
  public String home() { return "home" }
}

@RequestMapping("/super")
public class SuperController { }

@RequestMapping("/if")
interface MyInterface extends SuperInterface { }

@RequestMapping("/superif")
interface SuperInterface { }

3-1. 스프링 5.0

  • 새로운 함수형 스타일 웹 개발 지원.

  • 서블릿의 의존성 제거해 서블릿 컨테이너가 없어도 스프링 5 를 지원하는 자바로 만든 HTTP 서버라면
    스프링 5 애플리케이션을 띄울 수 있다.

  • 새로운 HTTP 요청과 응답의 추상화 - 불변 객체 ServerRequest, ServerResponse

  • 두 개의 함수를 이용해 개발 - HandlerFunction, RouterFunction

  • Mono, Flux 와 같은 리액티브 방식으로 개발

3-1-1. 스프링의 요청 처리

기존 웹 핸들러(컨트롤러) 가 웹 요청을 처리하는 방식
요청 매핑 → 요청 바인딩 → 핸들러 실행 → 핸들러 결과 처리

기존 방법

@RestController
public class MyController {
  @GetMapping("/hello/{name}")
  String hello(@PathVariable String name) {
    return "Hello " + name;
  }
}

RouterFunction, HandlerFunction 을 이용

@FunctionalInterface
public interface HandlerFunction<T extends ServerResponse> {
  Mono<T> handle(ServerRequest request);
}

@FunctionalInterface
public interface RouterFunction<T extends ServerResponse> { 
  Mono<HandlerFuncion<T>> route(ServerRequest request);
}

public static void main(String[] args) throws Exception {
  HandlerFunction helloHandler = (ServerRequest req) -> {
    String name = req.pathVariable("name");
    return ServerResponse.ok().syncBody("Hello " + name);
  }

  RouterFunction router = req -> RequestPredicates.path("/hello/{name}").test(req) ?    
      Mono.just(helloHandler) : Mono.empty();

  HttpHandler httpHandler = RouterFunctions.toHttpHandler(router);

  // Netty HTTP 서버 구동
  ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);
  HttpServer server = HttpServer.create("localhost", 8080);
  server.newHandler(adapter).block();

  System.in.read();
}

3-1-2. Mono/Flux

정보를 컨테이너에 담아서 전달한다. 피보탈에서 만든 ProjectReactor 에서 제공하고
Mono 는 단일 오브젝트, Flux 는 스트림 오브젝트 형식이다.

스프링 5 는 리액티브 프로그래밍 스타일로 스프링을 개발할 수 있도록 준비되어 있다.
ReactiveStreams 표준 API 를 지원하는 RxJava2 또는 ProjectReactor 를 사용할 수 있다.

함수형 스타일의 비동기 논블로킹 방식으로 동작하는 고성능 코드이다.

3-2. 자바 9

자바 9 에 Flow API 가 추가되었다. Flow API 는 ReactiveStreams 표준과 호환된다.
따라서 스프링의 Mono/Flux 와 Flow API 를 함께 사용해서 개발할 수 있다.