1. 程式人生 > >網關zuul——過濾器

網關zuul——過濾器

esp for 代碼 單例 stop system debug lte display

網關——過濾器

從網關組件請求流程分析,可以看出網關的核心類為ZuulServlet,所有的請求都是走到這裏來處理的!

技術分享圖片
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        try {
            this.init((HttpServletRequest)servletRequest, (HttpServletResponse)servletResponse);
            RequestContext context 
= 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(); } }
zuulServlet-service

從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——過濾器