Spring WebFlux๊ฐ ํฐ ํ์์ ์ด๋ค ๋ฐฉ์์ผ๋ก ๋์ํ๋์ง ์์๋ณด๊ณ ์ ํ๋ค.
Spring MVC ์ ๊ฒฝ์ฐ์๋ DispatcherServlet ๊ธฐ๋ฐ์ผ๋ก ์์ฒญ์ ๋ฐ์ ๋ท๋จ์ ์ฒ๋ฆฌ๊ฐ ์ด๋ฃจ์ด์ง๋ค. Spring WebFlux์ ๊ฒฝ์ฐ์๋ DispatcherServlet๊ณผ ๊ฐ์ด front controller ์ ์ญํ ์ ํด์ฃผ๋ ์น๊ตฌ๊ฐ ์กด์ฌํ๋ค.
์ผ๋จ ๊ฒฐ๋ก ๋ถํฐ ๋งํ๋ฉด ๋์ถฉ ๋ถ์ํด๋ณธ ๊ฒ๋ค์ ์์ฝํ์ ๋ ์๋ ๊ฐ์ ๊ทธ๋ฆผ์ด๋ค. (๊ฐ๋จํ๊ฒ ํํํด์ ์๋ต์ด ๋ง์ ์ ์๋ค.)
DispatcherHandler (WebHandler์ ๊ตฌํ์ฒด)
DispatcherHandler ๋ WebHandler ์ธํฐํ์ด์ค์ ๊ตฌํ์ฒด๋ก Spring Webflux์์์ front controller ์ญํ ์ ํ๋ค.
์๋๋ DispatchHandler ํด๋์ค์ด๋ค. Spring MVC์ ๋ง์ฐฌ๊ฐ์ง๋ก DispatcherHandler๋ HandlerMapping, HandlerAdapter, ๊ทธ๋ฆฌ๊ณ ์ถ๊ฐ์ ์ผ๋ก ResultHandler ์์ ์ฐ๊ด๊ด๊ณ๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
- handlerMapping : ์์ฒญ์ ์ด๋ค controller๊ฐ ์ฒ๋ฆฌํ ์ง ๊ฒฐ์
- handlerAdapter : HandlerMapping ์ผ๋ก ์ ํ๋ controller ๋๋ router ๋ฅผ ํธ์ถ
- handlerResultHandler : ๊ฒฐ๊ณผ๋ฅผ ์ฒ๋ฆฌํ๊ณ ์๋ต
public class DispatcherHandler implements WebHandler, PreFlightRequestHandler, ApplicationContextAware {
@Nullable
private List<HandlerMapping> handlerMappings;
@Nullable
private List<HandlerAdapter> handlerAdapters;
@Nullable
private List<HandlerResultHandler> resultHandlers;
public DispatcherHandler() {
}
public DispatcherHandler(ApplicationContext applicationContext) {
initStrategies(applicationContext);
}
@Nullable
public final List<HandlerMapping> getHandlerMappings() {
return this.handlerMappings;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
initStrategies(applicationContext);
}
protected void initStrategies(ApplicationContext context) {
Map<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerMapping.class, true, false);
ArrayList<HandlerMapping> mappings = new ArrayList<>(mappingBeans.values());
AnnotationAwareOrderComparator.sort(mappings);
this.handlerMappings = Collections.unmodifiableList(mappings);
Map<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerAdapter.class, true, false);
this.handlerAdapters = new ArrayList<>(adapterBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
Map<String, HandlerResultHandler> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerResultHandler.class, true, false);
this.resultHandlers = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(this.resultHandlers);
}
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
if (this.handlerMappings == null) {
return createNotFoundError();
}
if (CorsUtils.isPreFlightRequest(exchange.getRequest())) {
return handlePreFlight(exchange);
}
return Flux.fromIterable(this.handlerMappings)
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
.switchIfEmpty(createNotFoundError())
.flatMap(handler -> invokeHandler(exchange, handler))
.flatMap(result -> handleResult(exchange, result));
}
...
}
1. handle (ServerWebExchange serverWebExchange)
- request ๋ฅผ ๋ฐ์ handlerMapping ์ ํตํด ์ปจํธ๋กค๋ฌ๋ฅผ ๋งคํํ๊ณ handlerAdapter๋ฅผ ํตํด ๋ผ์ฐํฐ๋ฅผ ํธ์ถ ํ response๋ฅผ ๋ฐํํ๋ ๋ชจ๋ ์ผ๋ จ์ ๊ณผ์ ์ ๋ด์ ๋ฉ์๋์ด๋ค.
- serverWebExchange๋ ์์ฒญ(ServerHttpRequest)๊ณผ ์๋ต(ServerHttpResponse) ๋ชจ๋์ ๋ํ ์ปจํ ์คํธ๋ฅผ ์ ๊ณต ๋ฐ ์ ๊ทผ ๊ฐ๋ฅํ๋ค.
2. initStrategies(ApplicationContext context)
- ApplicationContext์ Bean(HandlerMapping, HandlerAdapter, HandlerResultHandler) ์ ์ฐพ์ ์ฃผ์ ํด์ค๋ค.
HttpWebHandlerAdapter (HttpHandler ์ ๊ตฌํ์ฒด)
์์ฒญ์ ๋ํ lowest level ๋์์ ๋งก๊ณ ์๋ HttpHandler ์ ๊ตฌํ์ฒด๋ก, WebHandler๋ก ์์ฒญ์ ๋๊ธฐ๊ธฐ ์ ์ ๋ด๋ถ์ ์ผ๋ก ๋์ํ๋ค.
์ ์์ค ๋ ๋ฒจ์ ๊ตฌํ์ฒด์ด๊ธฐ ๋๋ฌธ์ ๋ธ๋๋ฐ์ค ์์ญ์ผ๋ก ๊ฐ๋ฐ์๊ฐ ์ ๊ทผํ๊ณ ์์ ํ ์ผ์ด ์๋ ํด๋์ค๋ ์๋๋ค.
์ฆ, HttpWebHandlerAdapter ๋ HTTP ์์ฒญ์ ๋ฐ์ WebHandler(DispatcherHandler) ๋ก ์ ๋ฌํ๊ณ HTTP ์๋ต์ผ๋ก ๋ฐํํ๋ ์ญํ ์ ํ๋ค.
๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ ์ด ํด๋์ค์ ๋ํ ์ธ๊ธ์ด ํ์ํ ์ด์ ๋ DispatcherHandler๋ก ์ ๋ฌ ๋๊ธฐ ์ FilteringWebHandler๋ฅผ ํตํด WebFilter ํด๋์ค๋ค์ ํํฐ ์ฒด์ธ์ด ์คํ๋๊ธฐ ๋๋ฌธ์ด๋ค.
public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHandler {
...
@Override
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
if (this.forwardedHeaderTransformer != null) {
try {
request = this.forwardedHeaderTransformer.apply(request);
}
catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to apply forwarded headers to " + formatRequest(request), ex);
}
response.setStatusCode(HttpStatus.BAD_REQUEST);
return response.setComplete();
}
}
ServerWebExchange exchange = createExchange(request, response);
LogFormatUtils.traceDebug(logger, traceOn ->
exchange.getLogPrefix() + formatRequest(exchange.getRequest()) +
(traceOn ? ", headers=" + formatHeaders(exchange.getRequest().getHeaders()) : ""));
return getDelegate().handle(exchange)
.doOnSuccess(aVoid -> logResponse(exchange))
.onErrorResume(ex -> handleUnresolvedError(exchange, ex))
.then(Mono.defer(response::setComplete));
}
...
}
์ ์ฝ๋๋ฅผ ๋ณด๋ฉด getDelegate().handle(exchange) ๋ถ๋ถ์์ WebHandler ์ ๊ตฌํ์ฒด์ handle ๋ฉ์๋๊ฐ ์คํ๋๋ค.
WebHandler์ ๊ตฌํ์ฒด๋ก๋ DispatcherHandler ์ด์ธ์๋ FilteringWebHandler, ExceptionHandlingWebHandler ๋ฑ ์ฌ๋ฌ ๊ตฌํ์ฒด๊ฐ ์กด์ฌํ๋ค.
์๋ ์ฝ๋๋ ํํฐ์ฒด์ธ์ ํํฐ ์คํ ํจ์์ธ๋ฐ, ํํฐ๋ฅผ ์คํํ๊ณ ๋ ์ด์ ์คํํ ํํฐ๊ฐ ์์ผ๋ฉด ๋ค๋ฅธ webHandler์ handler ๋ฉ์๋๋ก ์์ํด์ฃผ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
public Mono<Void> filter(ServerWebExchange exchange) {
return Mono.defer(() ->
this.currentFilter != null && this.chain != null ?
invokeFilter(this.currentFilter, this.chain, exchange) :
this.handler.handle(exchange));
}
๋ง์ฝ ์๋ฒ์ ์์ฒญ ์ ์ ์ถ๊ฐ ๋ก์ง์ ๋ง๋ถ์ด๊ณ ์ถ๋ค๋ฉด WebFilter ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ ๊ตฌํ์ฒด๋ฅผ ์ถ๊ฐํด์ฃผ๋ฉด ๋๋ค.
์ฐธ๊ณ
https://docs.spring.io/spring-framework/reference/web/webflux/dispatcher-handler.html
https://blog.naver.com/PostView.naver?blogId=gngh0101&logNo=221538537388
'BACKEND > Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Spring Data ๊ด๋ จ ํด๋์ค ์ ๋ฆฌ (2) | 2023.09.18 |
---|---|
Spring WebFlux ๊ธฐ๋ฐ MDC ์ ์ฉํ๊ธฐ (+์ฝ๋ฃจํด) (0) | 2023.08.12 |
Spring WebFlux์ Programming Models (0) | 2023.02.20 |
Spring Actuator ์ฌ์ฉํด๋ณด๊ธฐ (0) | 2023.01.31 |
Spring Securirty 6 ์ด์ ๋ฒ์ ์์ h2-console 403 ์๋ฌ ๋๋ ๋ฌธ์ (2) | 2023.01.23 |