网关zuul——过滤器

Posted awsl

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网关zuul——过滤器相关的知识,希望对你有一定的参考价值。

网关——过滤器

从网关组件请求流程分析,可以看出网关的核心类为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——过滤器的主要内容,如果未能解决你的问题,请参考以下文章

服务网关zuul之四:zuul网关配置

SpringCloud学习--- Zuul详解(附代码包)

SpringCloud学习--- Zuul详解(附代码包)

springcloud zuul 网关

Spring Cloud:服务网关zuul过滤器

3.服务网关-Zuul