網關zuul——過濾器
網關——過濾器
從網關組件請求流程分析,可以看出網關的核心類為ZuulServlet,所有的請求都是走到這裏來處理的!
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { try { this.init((HttpServletRequest)servletRequest, (HttpServletResponse)servletResponse); RequestContext contextzuulServlet-service= RequestContext.getCurrentContext(); context.setZuulEngineRan(); try { this.preRoute(); } catch (ZuulException var12) { this.error(var12); this.postRoute(); return; }try { this.route(); } catch (ZuulException var13) { this.error(var13); this.postRoute(); return; } try { this.postRoute(); } catch (ZuulException var11) {this.error(var11); } } catch (Throwable var14) { this.error(new ZuulException(var14, 500, "UNHANDLED_EXCEPTION_" + var14.getClass().getName())); } finally { RequestContext.getCurrentContext().unset(); } }
從service方法中可以看出,preRoute()、route()、postRoute()、error()這4個方法為一套模板方法,定義了整個zuul組件的處理規則:
先執行preRoute()、再執行route(),然後是postRoute(),當任意環節出問題時,走到error()方法。
void postRoute() throws ZuulException { this.zuulRunner.postRoute(); } void route() throws ZuulException { this.zuulRunner.route(); } void preRoute() throws ZuulException { this.zuulRunner.preRoute(); } void error(ZuulException e) { RequestContext.getCurrentContext().setThrowable(e); this.zuulRunner.error(); }
從上述代碼可以看出,實際執行這套模板方法的時zuulRunner類
這次以preRoute()方法為例進行分析,最終preRoute()
在ZuulRunner中,調用的是FilterProcessor實例的preRoute();FilterProcessor類為單例模式,同時看其類名就可以知道該類是過濾器處理類;
public void preRoute() throws ZuulException { FilterProcessor.getInstance().preRoute(); }
查看在FilterProcessor類中preRoute()的具體實現
public void preRoute() throws ZuulException { try { //這裏是運行指定類型的過濾器 //只有類型為pre的過濾器才會被調用 this.runFilters("pre"); } catch (ZuulException var2) { throw var2; } catch (Throwable var3) { throw new ZuulException(var3, 500, "UNCAUGHT_EXCEPTION_IN_PRE_FILTER_" + var3.getClass().getName()); } } 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 = (ZuulFilter)list.get(i); Object result = this.processZuulFilter(zuulFilter); if (result != null && result instanceof Boolean) { bResult |= ((Boolean)result).booleanValue(); } } } return bResult; }
processZuulFilter(Zuulfilter filter)的具體內容
public Object processZuulFilter(ZuulFilter filter) throws ZuulException { RequestContext ctx = RequestContext.getCurrentContext(); boolean bDebug = ctx.debugRouting(); String metricPrefix = "zuul.filter-"; long execTime = 0L; 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(); } // 主要內容 ZuulFilterResult result = filter.runFilter(); ExecutionStatus s = result.getStatus(); execTime = System.currentTimeMillis() - ltime; 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); } } if (t != null) { throw t; } else { this.usageNotifier.notify(filter, s); return o; } } catch (Throwable var15) { if (bDebug) { Debug.addRoutingDebug("Running Filter failed " + filterName + " type:" + filter.filterType() + " order:" + filter.filterOrder() + " " + var15.getMessage()); } this.usageNotifier.notify(filter, ExecutionStatus.FAILED); if (var15 instanceof ZuulException) { throw (ZuulException)var15; } else { ZuulException ex = new ZuulException(var15, "Filter threw Exception", 500, filter.filterType() + ":" + filterName); ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime); throw ex; } }
runFilter()中的內容
public ZuulFilterResult runFilter() { ZuulFilterResult zr = new ZuulFilterResult(); if (!this.isFilterDisabled()) { //判斷是否執行filter if (this.shouldFilter()) { Tracer t = TracerFactory.instance().startMicroTracer("ZUUL::" + this.getClass().getSimpleName()); try { //執行filter中的run方法 Object res = this.run(); zr = new ZuulFilterResult(res, ExecutionStatus.SUCCESS); } catch (Throwable var7) { t.setName("ZUUL::" + this.getClass().getSimpleName() + " failed"); zr = new ZuulFilterResult(ExecutionStatus.FAILED); zr.setException(var7); } finally { t.stopAndLog(); } } else { zr = new ZuulFilterResult(ExecutionStatus.SKIPPED); } } return zr; }
從上面代碼可以看出,preRoute()方法為運行類型為”pre“的過濾器;從runFilter()方法可以看出,只有過濾器需要執行時才會執行過濾器中的run()方法;即過濾器中的run方法中包含了所有的過濾器要做的所有業務。
其他route(),postRoute(),error()中的代碼也遵循這一規則,只有過濾器類型不同這一點
總結:
網關組件Zuul中的過濾器:
在ZuulServlet中的service方法中定義過濾器的執行順序,按preRoute()、route()、postRoute()順序執行,error()時在出現異常時的處理規則。
追蹤preRoute()方法的執行可以得知,preRoute()經過了這3個類:ZuulServlet——>ZuulRunner——>FilterProcessor;
最終preRoute的具體實現規則是在FilterProcessor中定義的
在runFilters中定義了過濾器的類型:pre、route、post、error
在ZuulFilter抽象類中的runFilter定義了過濾器是否被執行以及執行的方法體為run()方法
綜上,要想添加一個能在網關中使用的自定義的過濾器;必須繼承ZuulFilter抽象類,同時在filterType方法中定義好過濾器類型:pre、route、post、error;shouldFilter方法必須返回true才能執行,過濾器的具體實現邏輯要定義在run()方法中。
網關zuul——過濾器