1.zuul是基于servlet 2.5,兼容servlet3.0,使用的是阻塞API,不支持长连接如websocket
2.Gateway基于spring5,Reactor和Spring boot2使用了非阻塞API,支持websocket,和spring完美集成,对开发者友好。
3.zuul2支持非阻塞API,但没有和spring cloud集成,且已经停止维护,不在考虑之列。
看spring-cloud-gateway-core包下的 spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayLoadBalancerClientAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayNoLoadBalancerClientAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayMetricsAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayRedisAutoConfiguration,\
org.springframework.cloud.gateway.discovery.GatewayDiscoveryClientAutoConfiguration
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.cloud.gateway.config.GatewayEnvironmentPostProcessor
package org.springframework.cloud.gateway.config;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.context.annotation.Configuration;
@Configuration
@AutoConfigureBefore(GatewayAutoConfiguration.class)
public class GatewayClassPathWarningAutoConfiguration {
private static final Log log = LogFactory
.getLog(GatewayClassPathWarningAutoConfiguration.class);
private static final String BORDER = "\n\n**********************************************************\n\n";
@Configuration
@ConditionalOnClass(name = "org.springframework.web.servlet.DispatcherServlet")
protected static class SpringMvcFoundOnClasspathConfiguration {
public SpringMvcFoundOnClasspathConfiguration() {
log.warn(BORDER
+ "Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway at this time. "
+ "Please remove spring-boot-starter-web dependency." + BORDER);
}
}
@Configuration
@ConditionalOnMissingClass("org.springframework.web.reactive.DispatcherHandler")
protected static class WebfluxMissingFromClasspathConfiguration {
public WebfluxMissingFromClasspathConfiguration() {
log.warn(BORDER + "Spring Webflux is missing from the classpath, "
+ "which is required for Spring Cloud Gateway at this time. "
+ "Please add spring-boot-starter-webflux dependency." + BORDER);
}
}
}
解释:
1.若存在springmvc的前端控制器org.springframework.web.servlet.DispatcherServlet,则报警,原因是使用非阻塞的API。
2.若不存在spring webflux的前端控制器org.springframework.web.reactive.DispatcherHandler,则报警,原因是需要使用非阻塞的API。
@Bean
public RoutePredicateHandlerMapping routePredicateHandlerMapping(
FilteringWebHandler webHandler, RouteLocator routeLocator,
GlobalCorsProperties globalCorsProperties, Environment environment) {
return new RoutePredicateHandlerMapping(webHandler, routeLocator,
globalCorsProperties, environment);
}
RoutePredicateHandlerMapping继承自AbstractHandlerMapping,在此步进行路径查找
@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>) 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 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()); }
*/
}
1.通过RouteLocator返回Route
关于Route的定义
可以看出url和gatewayFilter进行了绑定
2.将Route放入ServerWebExchange的属性中。
@Bean
public FilteringWebHandler filteringWebHandler(List globalFilters) {
return new FilteringWebHandler(globalFilters);
}