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

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

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 方法看一下调用链
2019102020052\_1.png
EmbeddedWebApplicationContext 这一块在spring-boot 原理有详细分析
2019102020052\_2.png
真正把ZuulServlet装入Servlet容器里
2019102020052\_3.png

2 ZuulServlet源码

zuulservlet 源码并不复杂,主要处理各种zuulfilter 的执行,先看一副图执行流程图
2019102020052\_4.png
首先先说明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;
        }
赞(1) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » spring-cloud 源码 zuul 调用过程(二)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏