본문 바로가기
Spring

Spring Webflux - DispatcherHandler

by 즐겁게살자 2021. 7. 12.
728x90

Spring weblfus 공식 레퍼런스 번역 & 요약

 

1.3 DispatcherHandler

 

스프링 웹플럭스도 스프링 MVC와 유사한 프론트 컨트롤러 패턴을 사용한다. 중앙 WebHandler가 요청을 받아, 실제 처리는 다른 컴포넌트에 위임하는데, DispatcherHandler가 바로 중앙 Webhandler다. 이 모델 덕분에 다양한 워크플로우를 지원할 수 있다.

 

DispatcherHandler는 스프링 설정에 따라 그에 맞는 컴포넌트로 위임한다. DispatcherHandler도 스프링 빈이며, ApplicationContextAware 인터페이스를 구현했기 때문에 실행 중인 컨텍스트에 접근할 수 있다. DispatcherHandler 빈을 WebHandler란 이름으로 정의하면 WebHttpHandlerBuilder가 이를 감지하고, WebHandler API에서 설명했던 체인에 추가한다.

 

웹플럭스 어플리케이션에서 사용하는 일반적인 스프링 설정은 다음과 같다.

  • WebHandler란 이름의 DispatcherHandler 빈
  • WebFilter, WebExceptionHandler 빈
  • 그 외 DispatcherHandler가 사용하는 빈
  • 기타 등등

아래 코드에서 보이는 것처럼, WebHttpHandlerBuilder 가 체인을 만들 땐 이 설정을 사용한다.

ApplicationContext context = ...
HttpHandler handler = WebHttpHandlerBuilder.applicationContext(context).build();

이땐 리턴된 HttpHandler는 서버 어댑터와 함께 요청을 처리한다.


1.3.1. Special Bean Types

Dispatcherhandler는 요청을 처리하고 그에 맞는 응답을 만들 때 사용하는 특별한 빈이 있다. "특별한 빈"이란, 웹플럭스 프레임워크가 동작하는데 필요한, 스프링이 관리하는 Object 인스턴스를 말한다. 이 빈들은 기본적으로 내장돼 있지만, 프로퍼티를 수정해서 확장하거나 커스텀 빈으로 대체할 수도 있다.

 

DispatcherHandler는 다음과 같은 빈을 감지한다. 저 수준에서 동작하는 다른 빈도 자동으로 추가될 수 있다는 점에 주의하라(Web Handler API 섹션의 Special bean types 참고).

 

Bean type Explanation
HandlerMapping 요청을 핸들러에 매핑한다. 매핑 기준은 HandlerMapping 구현체마다 다르다. (어노테이션을 선언한 컨트롤러, URL 패턴 매칭 등).
주로 쓰는 구현체는 @RequestMapping을 선언한 메소드를 찾는 RequestMappingHanderMapping
함수형 엔드포인트를 라우팅하는 RouterFunctionMapping
URI path 패턴으로 WebHandler를 찾는 SimpleUrlHandlerMapping 등이 있다.
HandlerAdapter HandlerAdapter가 핸드러를 실행하는 방법을 알고 있기 때문에, DispatcherHandler는 어떤 핸들러든지 받아 처리할 수 있다.
예를 들어 어노테이션을 선언한 컨트롤러를 실행하려면 리졸버가 필요한데, HandlerAdapter를 사용하면
DispatcherHandler는 이런 디테일을 몰라도 된다.
HandlerResultHandler 핸들러가 건네 준 결과를 처리하고 응답을 종료한다.
Result Handling를 참고하라.

1.3.2 WebFluxConfig

프레임워크 내부에서 사용하는 빈(Web Handler API에 있는 리스트와 DispatcherHandler)도 어플리케이션에서 직접 정의할 수 있다.

하지만 특별한 이유가 없다면 WebFlux Config로 시작하는 게 가장 좋다. 웹플럭스 config는 필요한 빈을 알아서 만들어 주고, 쉽게 설정을 커스텀할 수 있는 콜백 API를 제공한다.

스프링부트를 사용해도 이 웹플럭스 config로 초기화하며, 부트가 제공하는 옵션으로 좀 더 편리하게 설정을 관리할 수 있다.

1.3.3. Processing

 

DispatcherHandler는 다음과 같이 요청을 처리한다.

  • HandlerMapping을 뒤져 매칭되는 핸들러를 찾는다. 첫 번째로 매칭된 핸들러를 사용한다.
  • 핸들러를 찾으면 적당한 HandlerAdapter를 사용해 핸들러를 실행하고, HandlerResult를 돌려 받는다.
  • HandlerResult를 적절한 HandlerResultHandler로 넘겨 바로 응답을 만들거나 뷰로 렌더링하고 처리를 완료한다.

1.3.4. Result Handling 

HandlerAdapter는 핸들러 실행을 완료하고 나면, 실행 결과와 컨텍스트 정보를 감싸고 있는 HandlerResult를 반환한다. 이 HandlerResult는 HandlerResultHandler가 받아서 요청을 완료한다. 다음은 WebFlux Config에 정의돼 있는 HandlerResultHandler 구현체다.

Default Order

Result Handler Type Return Values Default Order
ResponseEntityResultHandler ResponseEntity, 보통 @Controller 에서 사용. 0
ServerResponseResultHandler ServerResponse, 보통 함수형 엔드포인트에서 사용. 0
ResponseBodyResultHandler @ResponseBody 메소드나 @RestController에서 리턴한 값을 처리 100
ViewResolutionResultHandler CharSequence, View, Model, Map, Rendering, 이나
다른 Object를 model attribute로 처리.

View Resolution 참고.
Integer.MAX_VALUE

1.3.5 Exceptions

HandlerAdapter가 리턴한 HandlerResult는 핸들러마다 다른 에러 처리 함수에 넘겨진다. 이 함수는 이럴 때 호출 된다.

  • 핸들러 실행에 실패한 경우 (예를 들어 @Controller에서).
  • HandlerResultHandler 가 핸들러가 리턴한 값을 처리 하는 데 실패한 경우.

핸들러가 리턴한 리액티브 타입이 데이터를 produce하기 전에 에러를 알아차릴 수만 있으면, 이 함수로 응답을 변경할 수 있다. (예를 들어 에러 status로).

 

이 덕분에 @Controller 클래스의 특정 메소드에 @ExceptionHandler를 선언할 수 있는 것이다.

스프링 MVC 에선 HandlerExceptionResolver가 이 역할을 담당한다. 여기서 중요한 건 MVC가 아니지만,

웹플럭스에선 핸들러를 선택하기 전 발생한 exception은 @ControllerAdvice로 처리할 수 없다는 것에 주의하라.

 

"Annotated Controller"섹션의 Managing Exceptions이나 WebHandler API 섹션의 Exceptions를 참고하라.


1.3.6. View Resolution

View resolution은 특정 view 기술에 얽매이지 않고 HTML 템플릿이나 모델을 사용해 브라우저에 렌더링하는 기법을 말한다.

Spring 웹플럭스에선 HandlerResultHandler가 ViewResolver 인스턴스를 사용해 view의 논리적인 이름을 가리키는 String과 View 인스턴스를 매핑한다. 이 View의 논리적인 이름을 가리키는 String과 View 인스턴스를 매핑한다. 이 View는 응답을 만들 때 사용된다.

 

Handling

ViewResolutionResultHandler로 넘겨진 HandlerResult는 핸들러가 리턴한 값과, 요청을 처리하면서 추가한 attribute를 포함한 model을 가지고 있다. 리턴 값은 다음 중 하나로 사용된다.

 

  • String, CharSequence
    • ViewResolver로 View를 만들 때 사용할 view의 논리적인 이름
  • void
    • 요청 path에 맞는 디폴트 view name에서 앞뒤 슬래쉬를 제거하고 view로 리졸브한다. view name이 제공되지 않았을 때나(e.g. model attriute를 리턴한 경우) 비동기 리턴 값일 때도(e.g. Mono가 비어 있을 때) 동일하게 처리한다.
  • Rendering
    • 여러 가지 view resolution 시나리오를 위한 API. 
  • Model, Map
    • model에 추가로 넣을 model attributes
  • 그 외
    • 그 외 다른 리턴값은(BeanUtils#isSimpleProperty가 true를 리턴하는 값은 예외) model에 추가할 model attribute로 간주한다. @ModelAttribute 어노테이션이 없으면 conventions와 클래스명으로 attribute name을 결정한다.

모델에는 비동기 리액티브 타입도 있을 수 있다(e.g. 리액터나 RxJava가 리턴한 값). 이런 model attribute는 AbstractView가 렌더링하기 전에 실제 값으로 바꿔준다. single-value 리액티브 타입은 비어있지 않다면 값 하나로 리졸브 되고, multi-value 리액티브 타입(e.g. Flux<T>)은 List<T>로 수집한다.

 

view resolution은 스프링 설정에 ViewResolutionResultHandler만 추가하면 된다. WebFlux Config는 view resolution을 위한 설정 API를 제공한다.

 

스프링 웹플럭스에 통합된 view 기술은 View Technologies에서 자세히 설명한다.

 

Readirecting

리다이렉트는 view name에 redirect:를 프리픽스로 붙이기만 하면 된다. UrlBasedViewResolver(하위 클래스도 포함)가 이를 리다이렉트 요청으로 판단한다. 프리픽스를 제외한 나머지 view name은 리다이렉트 URL로 사용한다. 동작 자체를 컨트롤러 RedirectView나 Rendering.redirectTo("abc").build()를 리턴했을 때와 동일하지만, 이 방법을 사용하면 컨트롤러가 직접 view name을 보고 처리한다. redirect:/some/resource 같은 값은 현재 어플리케이션에서 이동할 페이지를 찾고, redirect:https://example.com/arbitrary/path 같이 사용하면 해당 URL로 리다이렉트 한다.

 

Content Negotiation

content negotiation은 ViewResolutionResultHandler가 담당한다. 요청 미디어 타입과 View가 지원하는 미디어 타입을 비교해서, 첫 번째로 찾는 View를 사용한다.

 

스프링 웹플럭스는 HttpMessageWriter로 JSON, XML같은 미디어 타입을 만드는 HttpMessageWriterView를 지원한다. 보통은 WebFlux 설정을 통해 HttpMessageWriterView를 디폴트 view로 사용한다. 디폴트 뷰는 요청 미디어 타입과 일치하기만 하면 항상 사용되는 뷰다.

'Spring' 카테고리의 다른 글

WebFlux - Functional Endpoints  (0) 2021.09.12
Spring Webflux - Reactive Core  (0) 2021.07.05
Spring Webflux - Overview  (0) 2021.07.04

댓글