Rector Request -> Reactor-HttpHandler-Adapter -> Http-WebHandler-Adapter -> ExceptionHandling-WebHandler -> Filtering-WebHandler -> WebFilter -> DispatcherHandler -> HandlerMapping (get handler match the request) -> HandlerAdapter -> HandlerResultAdaptor
org.springframework.web.reactive.DispatcherHandler#initStrategies
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);
}
org.springframework.web.reactive.DispatcherHandler#handle
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
if (this.handlerMappings == null) {
return createNotFoundError();
}
return Flux.fromIterable(this.handlerMappings)
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
.switchIfEmpty(createNotFoundError())
.flatMap(handler -> invokeHandler(exchange, handler))
.flatMap(result -> handleResult(exchange, result));
}
RequestMappingHandlerAdapter
HandlerFunctionAdapter
SimpleHandlerAdapter -> spring cloud gateway goes this.
我要领养一只萌宠!
@RequestMapping("/game/animal")
@RestController
public class AnimalController {
private final List<String> ANIMALS = Arrays.asList("Monkey", "Tiger", "Elephant", "kangaroo", "Rabbit", "Goat", "Mouse", "Cat", "Dog", "Chicken", "Ant", "Bear");
@RequestMapping("/get")
public Mono<String> getAnimal(ServerHttpRequest request) {
List<String> fromList = request.getHeaders().get("from");
if (CollectionUtils.isEmpty(fromList)) {
return Mono.just("From is required in header!");
}
StringBuilder sb = new StringBuilder()
.append("Request from ")
.append(CollectionUtils.isEmpty(fromList) ? "Universal" : fromList.get(0))
.append("! ").append("Congratulations! You got a pet ")
.append(ANIMALS.get(new Random().nextInt(ANIMALS.size() - 1)))
.append("!");
return Mono.just(sb.toString());
}
}
永恒的经典,say hello to the world!
@Configuration
public class DemoRoutesConfiguration {
@Bean
public RouterFunction<ServerResponse> demoRoutes() {
return RouterFunctions.route(
GET("/helloWorld").and(accept(MediaType.APPLICATION_JSON)),
request -> ServerResponse.ok().syncBody("Hello World!")
);
}
}
所有的gateway请求最终通过org.springframework.cloud.gateway.handler.FilteringWebHandler进行处理。
org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#getHandlerInternal
@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
// don't handle requests on management port if set and different than server port
if (this.managementPortType == DIFFERENT && this.managementPort != null
&& exchange.getRequest().getURI().getPort() == this.managementPort) {
return Mono.empty();
}
exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());
return lookupRoute(exchange)
// .log("route-predicate-handler-mapping", Level.FINER) //name this
.flatMap((Function<Route, Mono<?>>) r -> {
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
if (logger.isDebugEnabled()) {
logger.debug(
"Mapping [" + getExchangeDesc(exchange) + "] to " + r);
}
exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
return Mono.just(webHandler);
}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
if (logger.isTraceEnabled()) {
logger.trace("No RouteDefinition found for ["
+ getExchangeDesc(exchange) + "]");
}
})));
}
protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
return this.routeLocator.getRoutes()
// individually filter routes so that filterWhen error delaying is not a
// problem
.concatMap(route -> Mono.just(route).filterWhen(r -> {
// add the current route we are testing
exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
return r.getPredicate().apply(exchange);
})
// instead of immediately stopping main flux due to error, log and
// swallow it
.doOnError(e -> logger.error(
"Error applying predicate for route: " + route.getId(),
e))
.onErrorResume(e -> Mono.empty()))
// .defaultIfEmpty() put a static Route not found
// or .switchIfEmpty()
// .switchIfEmpty(Mono.empty().log("noroute"))
.next()
// TODO: error handling
.map(route -> {
if (logger.isDebugEnabled()) {
logger.debug("Route matched: " + route.getId());
}
validateRoute(route, exchange);
return route;
});
/*
* TODO: trace logging if (logger.isTraceEnabled()) {
* logger.trace("RouteDefinition did not match: " + routeDefinition.getId()); }
*/
}
org.springframework.cloud.gateway.handler.FilteringWebHandler#handle
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
List<GatewayFilter> gatewayFilters = route.getFilters();
List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
combined.addAll(gatewayFilters);
// TODO: needed or cached?
AnnotationAwareOrderComparator.sort(combined);
if (logger.isDebugEnabled()) {
logger.debug("Sorted gatewayFilterFactories: " + combined);
}
return new DefaultGatewayFilterChain(combined).filter(exchange);
}