spring-cloud 源码 zuul 调用过程(二)

 

zuul 源码调用过程

 

1 Zuulservlet 装入tomcat容器

zuul 请求过程是怎么被怎么理的,上一编我们看到ZuulServerlet实例化并被封装进ServletRegistrationBean,且托管到spring容器里,那么该servlet是怎么放进tomcat里的,注意ServletRegistrationBean 实现 ServletContextInitializer

    @Bean
    @ConditionalOnMissingBean(name = "zuulServlet")
    public ServletRegistrationBean zuulServlet() {
        ServletRegistrationBean servlet = new ServletRegistrationBean(new ZuulServlet(),
                this.zuulProperties.getServletPattern());
        // The whole point of exposing this servlet is to provide a route that doesn't
        // buffer requests.
        servlet.addInitParameter("buffer-requests", "false");
        return servlet;
    }

从 ServletRegistrationBean 的getServlet 方法看一下调用链
《spring-cloud 源码 zuul 调用过程(二)》
EmbeddedWebApplicationContext 这一块在spring-boot 原理有详细分析
《spring-cloud 源码 zuul 调用过程(二)》
真正把ZuulServlet装入Servlet容器里
《spring-cloud 源码 zuul 调用过程(二)》

2 ZuulServlet源码

zuulservlet 源码并不复杂,主要处理各种zuulfilter 的执行,先看一副图执行流程图
《spring-cloud 源码 zuul 调用过程(二)》
首先先说明Zuulfilter 有四种 pre(前置),route(路由定位),post(执行后),erro(出错),执行流程如上图,执行代码如下面

  private ZuulRunner zuulRunner;


    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);

        String bufferReqsStr = config.getInitParameter("buffer-requests");
        boolean bufferReqs = bufferReqsStr != null && bufferReqsStr.equals("true") ? true : false;

        zuulRunner = new ZuulRunner(bufferReqs);
    }

    @Override
    public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {
        try {
            //省去一些代码
            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();
        }
    }

    /** * executes "post" ZuulFilters * * @throws ZuulException */
    void postRoute() throws ZuulException {
        zuulRunner.postRoute();
    }

    /** * executes "route" filters * * @throws ZuulException */
    void route() throws ZuulException {
        zuulRunner.route();
    }

    /** * executes "pre" filters * * @throws ZuulException */
    void preRoute() throws ZuulException {
        zuulRunner.preRoute();
    }

    /** * initializes request * * @param servletRequest * @param servletResponse */
    void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {
        zuulRunner.init(servletRequest, servletResponse);
    }

    /** * sets error context info and executes "error" filters * * @param e */
    void error(ZuulException e) {
        RequestContext.getCurrentContext().setThrowable(e);
        zuulRunner.error();
    }

4 ZuulFilter 执行实现

跟踪源码发现核处理在FilterProcessor 类上,但逻辑也不复杂

   public Object runFilters(String sType) throws Throwable {
        //省去一些代码
        boolean bResult = false;
        //据filter类型,获取排过序的filter
        List<ZuulFilter> list = FilterLoader.getInstance().getFiltersByType(sType);
        if (list != null) {
            for (int i = 0; i < list.size(); i++) {
                ZuulFilter zuulFilter = list.get(i);
                //处理filter执行
                Object result = processZuulFilter(zuulFilter);
                if (result != null && result instanceof Boolean) 
                    bResult |= ((Boolean) result);
                }
            }
        }
        return bResult;
    }

    /** * Processes an individual ZuulFilter. This method adds Debug information. Any uncaught Thowables are caught by this method and converted to a ZuulException with a 500 status code. * * @param filter * @return the return value for that filter * @throws ZuulException */
    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内存方法
            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);
                    }
                    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;
            }
        }
    }

ZuulFilter 执行源码

    public ZuulFilterResult runFilter() {
        ZuulFilterResult zr = new ZuulFilterResult();
        if (!isFilterDisabled()) {
            //是否执行
            if (shouldFilter()) {
                Tracer t = TracerFactory.instance().startMicroTracer("ZUUL::" + this.getClass().getSimpleName());
                try {
                    //执行,run方法就是具体filter 实现的run方法
                    Object res = run();
                    zr = new ZuulFilterResult(res, ExecutionStatus.SUCCESS);
                } catch (Throwable e) {
                    t.setName("ZUUL::" + this.getClass().getSimpleName() + " failed");
                    zr = new ZuulFilterResult(ExecutionStatus.FAILED);
                    zr.setException(e);
                } finally {
                    t.stopAndLog();
                }
            } else {
                zr = new ZuulFilterResult(ExecutionStatus.SKIPPED);
            }
        }
        return zr;
    }
    原文作者:Spring Cloud
    原文地址: https://blog.csdn.net/yangyangiud/article/details/80504255
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞