zuul 和 gateway 原理分析
Posted lisin-lee-cooper
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了zuul 和 gateway 原理分析相关的知识,希望对你有一定的参考价值。
一. zuul 原理分析
zuulServlet 源码
public class ZuulServlet extends HttpServlet
private ZuulRunner zuulRunner;
public void init(ServletConfig config) throws ServletException
...
public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException
...
service 方法
try
init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
// Marks this request as having passed through the "Zuul engine", as opposed to servlets
// explicitly bound in web.xml, for which requests will not have the same data attached
RequestContext context = RequestContext.getCurrentContext();
context.setZuulEngineRan();
try
preRoute();
catch (ZuulException e)
error(e);
postRoute();
return;
try
route();
catch (ZuulException e)
error(e);
postRoute();
return;
try
postRoute();
catch (ZuulException e)
error(e);
return;
catch (Throwable e)
error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName()));
finally
RequestContext.getCurrentContext().unset();
processZuulFilter 方法
public Object processZuulFilter(ZuulFilter filter) throws ZuulException
RequestContext ctx = RequestContext.getCurrentContext();
boolean bDebug = ctx.debugRouting();
final String metricPrefix = "zuul.filter-";
long execTime = 0;
String filterName = "";
try
long ltime = System.currentTimeMillis();
filterName = filter.getClass().getSimpleName();
RequestContext copy = null;
Object o = null;
Throwable t = null;
if (bDebug)
Debug.addRoutingDebug("Filter " + filter.filterType() + " " + filter.filterOrder() + " " + filterName);
copy = ctx.copy();
//执行ZuulFilter的runFilter逻辑
ZuulFilterResult result = filter.runFilter();
ExecutionStatus s = result.getStatus();
//执行耗时统计(可以发现Zuul还没有完善这个功能,只是形成了框架)
execTime = System.currentTimeMillis() - ltime;
//处理执行结果,无论成功与否,都记录了debug日志
switch (s)
case FAILED:
t = result.getException();
ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime);
break;
case SUCCESS:
o = result.getResult();
ctx.addFilterExecutionSummary(filterName, ExecutionStatus.SUCCESS.name(), execTime);
if (bDebug)
Debug.addRoutingDebug("Filter " + filterName + " TYPE:" + filter.filterType() + " ORDER:" + filter.filterOrder() + " Execution time = " + execTime + "ms");
Debug.compareContextState(filterName, copy);
break;
default:
break;
if (t != null) throw t;
//目前作为空壳存在,可见是为了方便扩展
usageNotifier.notify(filter, s);
return o;
catch (Throwable e)
if (bDebug)
Debug.addRoutingDebug("Running Filter failed " + filterName + " type:" + filter.filterType() + " order:" + filter.filterOrder() + " " + e.getMessage());
usageNotifier.notify(filter, ExecutionStatus.FAILED);
if (e instanceof ZuulException)
throw (ZuulException) e;
else
ZuulException ex = new ZuulException(e, "Filter threw Exception", 500, filter.filterType() + ":" + filterName);
ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime);
throw ex;
Zuul提供了com.netflix.zuul.filters.StaticResponseFilter和com.netflix.zuul.filters.SurgicalDebugFilter两种抽象类,StaticResponseFilter会将请求直接处理并返回,即不会经过路由链路;SurgicalDebugFilter则会将请求路由到微服务中;
zuulServlet 由于底层是servlet, 易于扩展, 可以构建相应的filter 来按照顺序做登陆校验和权限校验。
二.gateway原理分析
gateway 自动装配类
@Configuration
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
@EnableConfigurationProperties
@AutoConfigureBefore(HttpHandlerAutoConfiguration.class)
@AutoConfigureAfter(GatewayLoadBalancerClientAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class)
@ConditionalOnClass(DispatcherHandler.class)
public class GatewayAutoConfiguration
...
@Bean
@ConditionalOnBean(DispatcherHandler.class)
public ForwardRoutingFilter forwardRoutingFilter(DispatcherHandler dispatcherHandler)
return new ForwardRoutingFilter(dispatcherHandler);
...
protected Mono<?> getHandlerInternal(ServerWebExcha nge exchange)
exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getClass().getSimpleName());
return lookupRoute(exchange)
//根据exchange找匹配的route
// .log("route-predicate-handler-mapping", Level.FINER) //name this
.flatMap((Function<Route, Mono<?>>) r -> //替换请求attributes值
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);//执行filter的handle方法
).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()
.filterWhen(route -> //找到匹配的route,一个route包含一个filter链
// add the current route we are testing
exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, route.getId());
return route.getPredicate().apply(exchange);
)
// .defaultIfEmpty() put a static Route not found
// or .switchIfEmpty()
// .switchIfEmpty(Mono.<Route>empty().log("noroute"))
.next()
.map(route ->
if (logger.isDebugEnabled())
logger.debug("Route matched: " + route.getId());
validateRoute(route, exchange);
return route;
);
@Override
public Flux<Route> getRoutes()
return this.routeDefinitionLocator.getRouteDefinitions()
.map(this::convertToRoute)
//TODO: error handling
.map(route ->
if (logger.isDebugEnabled())
logger.debug("RouteDefinition matched: " + route.getId());
return route;
);
servlet,但使用了webflux,多嵌套了一层框架 ,大量使用的流式编程;
提供了非常丰富的filter实现和灵活的RoutePredicateFactory(route匹配规则),提供了限流接口RedisRateLimiter的实现,功能更加全面。
以上是关于zuul 和 gateway 原理分析的主要内容,如果未能解决你的问题,请参考以下文章
最全面的改造Zuul网关为Spring Cloud Gateway(包含Zuul核心实现和Spring Cloud Gateway核心实现)
0601-Zuul构建API Gateway-API gateway简介