请先关注 [低调大师] 公众号 优秀的自媒体个人博客,低调大师,许军

低调大师

您现在的位置是:首页>文章详情

文章详情

Zuul源码阅读

2018-10-02 83热度

Motivation

说一下,为什么要阅读Netflix Zuul,最近在看alibaba/Sentinel 在网关方面的应用。发现网关的设计模式有很多通用的地方。Netflix Zuul 对比Zuul2 更能直接的看出网关的主要功能和核心设计,易于上手,所以选择这个。同时也再次实践一下怎么高效阅读源代码。

Design and Function

Zuul 的主要功能,包括,鉴权,路由,流量监控,负载,实时响应(动态配置和开关),错误处理。

zuul

这张图就是根据这些功能提出的设计,通过Filter 将整个过程连接起来,

可扩展性:

  1. 在不同阶段做不同的处理,做隔离。
  2. 通过groovy 脚本加载来实现动态加载新的filter。

ZuulFilter

下面我们就来看总重要的 ZuulFilter 的设计吧,首先是类结构图

先看最基本的IZuulFilter 接口, 定义了两个方法,这个filter 要不要执行,怎么执行。

public interface IZuulFilter { /** * a "true" return from this method means that the run() method should be invoked * * @return true if the run() method should be invoked. false will not invoke the run() method */ boolean shouldFilter(); /** * if shouldFilter() is true, this method will be invoked. this method is the core method of a ZuulFilter * * @return Some arbitrary artifact may be returned. Current implementation ignores it. * @throws ZuulException if an error occurs during execution. */ Object run() throws ZuulException; } 

这里暂时提出疑问,throw ZuulException 会怎样?,返回任意result 怎么处理。

下面来看 Abstratct ZuulFilter类:

/** * Base abstract class for ZuulFilters. The base class defines abstract methods to define: * filterType() - to classify a filter by type. Standard types in Zuul are "pre" for pre-routing filtering, * "route" for routing to an origin, "post" for post-routing filters, "error" for error handling. * We also support a "static" type for static responses see StaticResponseFilter. * Any filterType made be created or added and run by calling FilterProcessor.runFilters(type) * <p/> * filterOrder() must also be defined for a filter. Filters may have the same filterOrder if precedence is not * important for a filter. filterOrders do not need to be sequential. * <p/> * ZuulFilters may be disabled using Archius Properties. * <p/> * By default ZuulFilters are static; they don't carry state. This may be overridden by overriding the isStaticFilter() property to false * * @author Mikey Cohen * Date: 10/26/11 * Time: 4:29 PM */ public abstract class ZuulFilter implements IZuulFilter, Comparable<ZuulFilter> { private final AtomicReference<DynamicBooleanProperty> filterDisabledRef = new AtomicReference<>(); /** * to classify a filter by type. Standard types in Zuul are "pre" for pre-routing filtering, * "route" for routing to an origin, "post" for post-routing filters, "error" for error handling. * We also support a "static" type for static responses see StaticResponseFilter. * Any filterType made be created or added and run by calling FilterProcessor.runFilters(type) * * @return A String representing that type */ abstract public String filterType(); /** * filterOrder() must also be defined for a filter. Filters may have the same filterOrder if precedence is not * important for a filter. filterOrders do not need to be sequential. * * @return the int order of a filter */ abstract public int filterOrder(); public int compareTo(ZuulFilter filter) { return Integer.compare(this.filterOrder(), filter.filterOrder()); } } 

根据设计图,我们知道Filter有三个阶段 分别是 pre, route,post, 这里的filterType 就是指定filter type(不同type的执行顺序不一样)。filterOrder 方法就是指定相同type 下filter的执行顺序了。同时也是实现 Comparable接口的原因了。

关于自定义 type,我们稍后再看。

那我们来看看 这些type的顺序是怎么指定的,

/** * Zuul Servlet filter to run Zuul within a Servlet Filter. The filter invokes pre-routing filters first, * then routing filters, then post routing filters. Handled exceptions in pre-routing and routing * call the error filters, then call post-routing filters. Errors in post-routing only invoke the error filters. * Unhandled exceptions only invoke the error filters * * @author Mikey Cohen * Date: 10/12/11 * Time: 2:54 PM */ public class ZuulServletFilter implements Filter { private ZuulRunner zuulRunner; @Override public void init(FilterConfig filterConfig) throws ServletException { String bufferReqsStr = filterConfig.getInitParameter("buffer-requests"); boolean bufferReqs = bufferReqsStr != null && bufferReqsStr.equals("true") ? true : false; zuulRunner = new ZuulRunner(bufferReqs); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { try { init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse); try { preRouting(); } catch (ZuulException e) { error(e); postRouting(); return; } // Only forward onto to the chain if a zuul response is not being sent if (!RequestContext.getCurrentContext().sendZuulResponse()) { filterChain.doFilter(servletRequest, servletResponse); return; } try { routing(); } catch (ZuulException e) { error(e); postRouting(); return; } try { postRouting(); } catch (ZuulException e) { error(e); return; } } catch (Throwable e) { error(new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_FROM_FILTER_" + e.getClass().getName())); } finally { RequestContext.getCurrentContext().unset(); } } } 

现在 看到了,ZuulFilter是通过实现在Servlet Filter的生命周期中实现的。那现在我们可以猜想 preRouting() 里会把所有的pre Type 按顺序执行:

 /** * runs all "pre" filters. These filters are run before routing to the orgin. * * @throws ZuulException */ public void preRoute() throws ZuulException { try { runFilters("pre"); } catch (ZuulException e) { throw e; } catch (Throwable e) { throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_PRE_FILTER_" + e.getClass().getName()); } } /** * runs all filters of the filterType sType/ Use this method within filters to run custom filters by type * * @param sType the filterType. * @return * @throws Throwable throws up an arbitrary exception */ public Object runFilters(String sType) throws Throwable { if (RequestContext.getCurrentContext().debugRouting()) { Debug.addRoutingDebug("Invoking {" + sType + "} type filters"); } boolean bResult = false; List<ZuulFilter> list = FilterLoader.getInstance().getFiltersByType(sType); if (list != null) { for (int i = 0; i < list.size(); i++) { ZuulFilter zuulFilter = list.get(i); Object result = processZuulFilter(zuulFilter); if (result != null && result instanceof Boolean) { bResult |= ((Boolean) result); } } } return bResult; } 

从代码可以看出process根据列表里的filter顺序执行,顺序在返回前就按order 排序了,这样,当一个 preFilter 执行抛出 ZuulException 之后,pre阶段就结束了,进到最初ServletFilter的后续阶段。

所以到这里为止,我们就知道Zuul是怎么工作和扩展的了,大家就可以根据自己的需要进行扩展了。

收藏 (0)

相关文章

    文章评论

    共有0条评论来说两句吧...