Spring WebFlux는 Spring MVC와 마찬가지로 프론트 컨트롤러 패턴을 사용하여 설계되었습니다. WebFlux의 프론트 컨트롤러인 DispatcherHandler는 요청 처리의 핵심 알고리즘을 제공하며, 다양한 위임 컴포넌트를 통해 실제 처리가 이루어집니다. 이번 글에서는 DispatcherHandler의 구조와 역할을 상세히 살펴보겠습니다.
WebFlux 구성 요소
일반적인 WebFlux 설정은 다음과 같은 구성 요소를 포함합니다:
webHandler
빈으로 선언된 DispatcherHandlerWebFilter
및WebExceptionHandler
Bean- DispatcherHandler 관련 Bean
HttpWebHandlerAdapter
HttpWebHandlerAdapter는 HttpHandler의 구현체로, 가장 저수준의 HTTP 요청 처리를 담당합니다. 이 클래스는 WebHandler(주로 DispatcherHandler)로 요청을 전달하고, 처리된 결과를 HTTP 응답으로 반환하는 역할을 합니다.
역할과 동작
- 요청 전달: HTTP 요청을 DispatcherHandler로 전달합니다.
- 필터 체인 실행: FilteringWebHandler를 통해 WebFilter 클래스들의 필터 체인이 실행됩니다.
저수준 구현체이기 때문에 일반적으로 개발자가 직접 수정할 일은 없습니다. 그러나 필터링 동작을 이해하기 위해 이 클래스의 역할을 파악하는 것이 중요합니다.
DispatcherHandler
DispatcherHandler는 스프링 설정으로부터 필요한 위임 컴포넌트(예: HandlerMapping, HandlerAdapter)를 검색합니다. 또한, 스프링 빈으로 등록되며 ApplicationContextAware 인터페이스를 구현하여 실행 중인 애플리케이션 컨텍스트에 접근합니다. DispatcherHandler가 webHandler라는 이름으로 선언되어 있다면, WebHttpHandlerBuilder에 의해 자동으로 검색됩니다.
Bean 타입
DispatcherHandler는 다양한 빈을 검색하여 요청 처리 과정에서 활용합니다. 이러한 빈은 주로 스프링이 제공하는 WebFlux 계약을 구현합니다.
Bean | 설명 |
---|---|
HandlerMapping | 요청과 핸들러를 연결합니다. 주로 URL 패턴 매핑이나 애너테이션 기반 매핑을 지원합니다. 주요 구현체는 RequestMappingHandlerMapping , RouterFunctionMapping , SimpleUrlHandlerMapping 등이 있습니다. |
HandlerAdapter | 핸들러가 호출될 수 있도록 지원합니다. DispatcherHandler는 이 빈을 통해 세부 구현에 구애받지 않고 핸들러를 호출할 수 있습니다. |
HandlerResultHandler | 핸들러의 반환값을 처리하고 최종 응답을 생성합니다. |
요청 처리 흐름
DispatcherHandler는 다음과 같은 순서로 요청을 처리합니다:
- Handler 검색: 각
HandlerMapping
빈을 호출하여 적합한 핸들러를 찾습니다. 첫 번째로 매칭된 핸들러를 사용합니다. - Handler 호출: 적절한
HandlerAdapter
를 사용하여 핸들러를 실행하고 반환값을HandlerResult
로 포장합니다. - 결과 처리:
HandlerResultHandler
를 사용하여 응답을 생성합니다. 응답은 직접 작성하거나 뷰 렌더링을 통해 완료됩니다.
반환값 처리 (Result Handling)
핸들러의 반환값은 HandlerAdapter
를 통해 HandlerResult
로 감싸지며, 추가 컨텍스트 정보도 포함됩니다. HandlerResult
는 첫 번째로 매칭된 HandlerResultHandler
로 처리됩니다.
주요 HandlerResultHandler 구현체
HandlerResultHandler 타입 | 반환 값 |
---|---|
ResponseEntityResultHandler | @Controller에서 생성된 ResponseEntity |
ServerEntityResultHandler | 함수형 엔드포인트에서 생성된 ServerResponse |
ResponseBodyResultHandler | @ResponseBody 메소드 또는 @RestController 반환값 |
ViewResolutionResultHandler | View , Model , Map 등을 뷰로 처리 |
Exception Handling
DispatcherHandler는 예외 처리를 위해 DispatchExceptionHandler
를 사용할 수 있습니다. 핸들러 실행 중 또는 그 이전 단계에서 발생한 예외를 처리할 수 있으며, 비동기 요청에서 예외 처리가 미루어질 수 있습니다.
@RestController
class ExampleController {
@GetMapping("/example")
fun exampleEndpoint(): ResponseEntity<String> {
throw IllegalArgumentException("예외 발생!")
}
@ExceptionHandler(IllegalArgumentException::class)
fun handleIllegalArgument(ex: IllegalArgumentException): ResponseEntity<String> {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("에러 처리: ${ex.message}")
}
}
View Resolution
Spring WebFlux의 뷰 해석(View Resolution)은 HTML 템플릿과 모델 데이터를 렌더링하여 브라우저에 표시하는 과정입니다. ViewResolver
인스턴스를 사용하여 문자열 뷰 이름을 실제 뷰로 해석합니다.
뷰 해석 처리 방식
- Spring, CharSequence: 문자열로 된 뷰 이름을
ViewResolver
가 해석합니다. - void: 요청 경로를 기반으로 기본 뷰를 선택합니다.
- Rendering: 뷰 해석 시나리오에 적합한 API를 제공합니다.
- Model, Map: 요청 모델에 추가 속성을 설정합니다.
@Controller
class ExampleViewController {
@GetMapping("/view")
fun showView(model: Model): String {
model.addAttribute("message", "Hello, WebFlux!")
return "exampleView"
}
}
Content Negotiation
ViewResolutionResultHandler
는 클라이언트의 요청 미디어 타입과 뷰가 지원하는 미디어 타입을 비교하여 적합한 뷰를 선택합니다. JSON, XML 등 다양한 포맷을 지원하기 위해 HttpMessageWriterView
를 사용할 수 있습니다.
@Configuration
class WebConfig : WebFluxConfigurer {
override fun configureContentTypeResolver(resolver: RequestedContentTypeResolverBuilder) {
resolver.favorPathExtension(true).favorParameter(true)
}
}
HandlerAdapter
HandlerAdapter는 DispatcherHandler가 다양한 유형의 핸들러를 호출할 수 있도록 지원하는 핵심 컴포넌트입니다. 핸들러의 종류에 따라 다양한 HandlerAdapter 구현체가 존재하며, 각 구현체는 특정 핸들러 타입에 대한 호출 로직을 담당합니다.
주요 HandlerAdapter 구현체
SimpleHandlerAdapter
:HttpRequestHandler
인터페이스를 구현한 핸들러를 처리합니다.HttpRequestHandlerAdapter
: Spring의HttpRequestHandler
인터페이스를 구현한 핸들러를 처리합니다.ControllerClassNameHandlerAdapter
: 클래스 이름 규칙을 기반으로 핸들러를 매핑하고 실행합니다.RequestMappingHandlerAdapter
:@RequestMapping
어노테이션을 사용하여 매핑된 핸들러를 처리합니다.
DispatcherHandler는 각 요청에 대해 적합한 HandlerAdapter를 찾아 핸들러를 실행합니다. 이를 통해 DispatcherHandler는 핸들러의 실제 타입에 의존하지 않고 요청을 처리할 수 있습니다.
ViewResolver
ViewResolver는 뷰 이름(View Name)을 실제 뷰 객체(View Object)로 변환하는 역할을 담당합니다. Spring WebFlux는 다양한 ViewResolver 구현체를 제공하며, 각 구현체는 특정 뷰 기술(예: Thymeleaf, FreeMarker, JSP)을 지원합니다.
주요 ViewResolver 구현체
InternalResourceViewResolver
: JSP와 같은 내부 리소스 뷰를 처리합니다.ThymeleafViewResolver
: Thymeleaf 템플릿 엔진을 사용하는 뷰를 처리합니다.FreeMarkerViewResolver
: FreeMarker 템플릿 엔진을 사용하는 뷰를 처리합니다.
DispatcherHandler는 뷰 이름을 기반으로 적절한 ViewResolver를 선택하고, ViewResolver는 해당 뷰 이름을 해석하여 실제 뷰 객체를 생성합니다. 생성된 뷰 객체는 모델 데이터를 사용하여 뷰를 렌더링하고, 렌더링된 결과는 클라이언트에게 응답됩니다.
참고
- Web on Reactive Stack
- https://docs.spring.io/spring-framework/reference/web/webflux/dispatcher-handler.html