zuul1源码解析-请求处理流程

1.zuul是什么
Zuul 是 Netflix 开源的微服务网关,可以将非服务核心功能移至到网关中,比如:鉴权,请求日志等

2.zuul1系统架构图
zuul1系统架构
请求经过ZuulServlet,然后执行各种类型的过滤器链处理完毕之后,将处理后的结果响应出去。而且Zuul强化了其过滤器功能,支持热加载过滤器。

  1. 源码解析
    此次源码分析的版本是1.x,如果你看的是2.0版本以上的请忽略本文章。
    3.1 servlet源码解析
    我们知道一个web项目少不了一个servlet,它也是服务处理的入口和出口。所以先从ZuulServlet开始介绍。
public class ZuulServlet extends HttpServlet {

      private static final long serialVersionUID = -3374242278843351500L;
    // zuul执行器,ZuulServlet直接访问这个类的方法
    private ZuulRunner zuulRunner;

    /**
     * 初始化ZuulRunner
     * @param config
     * @throws ServletException
     */
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        // 可以在servletConfig的配置中添加buffer-requests参数,表示缓存请求
        String bufferReqsStr = config.getInitParameter("buffer-requests");
        boolean bufferReqs = bufferReqsStr != null && bufferReqsStr.equals("true") ? true : false;
        // 创建ZuulRunner对象
        zuulRunner = new ZuulRunner(bufferReqs);
    }

    /**
     * 处理请求的核心方法
     * @param servletRequest 请求对象
     * @param servletResponse 响应对象
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {
        try {
            // 包装http请求和响应对象
            init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);

            // 请求上下文对象
            RequestContext context = RequestContext.getCurrentContext();
            // 表示zuul已经在执行
            context.setZuulEngineRan();

            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();
    }

    /**
     *  初始化请求对象
     *
     * @param servletRequest
     * @param servletResponse
     */
    void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {
        zuulRunner.init(servletRequest, servletResponse);
    }

    /**
     * error过滤器
     *
     * @param e
     */
    void error(ZuulException e) {
        // 设置异常信息
        RequestContext.getCurrentContext().setThrowable(e);

        zuulRunner.error();
    }

3.1.1 处理流程
通过service方法,可以看出整个servlet的处理流程:
pre异常: pre -> error -> post
route异常: pre -> route -> error -> post
post异常: pre -> route -> post -> error
正常: pre -> route -> post
[说明]
pre:表示路由的前置过滤器链,route:表示路由的过滤器链,post:表示路由的后置过滤器链,error:表示路由错误过滤器链。
由此可见,责任链模式是zuul的核心(如果对这个设计模式不清楚的同学,可以参考:责任链模式

3.1.2 各种过滤器类型解析
由于pre,post,route,error的最终处理逻辑都是一样的,所以只介绍pre过滤器。
上面调用preRoute方法时,最终会调用到ZuulRunner的preRoute方法。

ZuulServlet.java

    void preRoute() throws ZuulException {
        zuulRunner.preRoute();
    }


而Zuul执行preRoute时,又是调用FilterProcessor的方法。由于FilterProcessor创建多个实例是没有任何意义的,所以使用了单例模式(参考:单例模式)

ZuulRunner.java

   public void preRoute() throws ZuulException {
        FilterProcessor.getInstance().preRoute();
    }

FilterProcessor中又调用了自身的runFilters方法

FilterProcessor.java

    public void preRoute() throws ZuulException {
        try {
            runFilters("pre");
        } catch (ZuulException e) {
            throw e;
        } catch (Throwable e) {
            // 其他异常转换为ZuulException异常
            throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_PRE_FILTER_" + e.getClass().getName());
        }
    }

    /**
     *
     * 运行某种类型的所有过滤器
     *
     * @param sType 过滤器类型:pre,route,post,error
     * @return
     * @throws Throwable throws up an arbitrary exception
     */
    public Object runFilters(String sType) throws Throwable {
       if (RequestContext.getCurrentContext().debugRouting()) {
            // 如果开启了路由的请求日志 ,将日志添加到RequestContext对象中
            Debug.addRoutingDebug("Invoking {" + sType + "} type filters");
        }
        boolean bResult = false;
        // 【1】
        List<ZuulFilter> list = FilterLoader.getInstance().getFiltersByType(sType);
        if (list != null) {
            for (int i = 0; i < list.size(); i++) {
                ZuulFilter zuulFilter = list.get(i);
                // 【2】
                Object result = processZuulFilter(zuulFilter);
                if (result != null && result instanceof Boolean) {
                    // 如果结果是布尔类型
                    bResult |= ((Boolean) result);
                }
            }
        }
        return bResult;
    }


通过上面的逻辑可以知道,过滤器运行的步骤:
(1) 添加路由日志
(2) 根据过滤器的优先级排序整个过滤器链
(3) 依次执行过滤器,如果是布尔类型汇总结果

关键位置分析:
【1】调用FilterLoader(获取改对象也是使用单例模式)的getFiltersByType方法

/**
     * 返回指定的过滤器类型的过滤器列表(已经排序)
     *
     * @param filterType 过滤器类型
     * @return a List<ZuulFilter>
     */
    public List<ZuulFilter> getFiltersByType(String filterType) {
        // 检查缓存
        List<ZuulFilter> list = hashFiltersByType.get(filterType);
        if (list != null) return list;

        list = new ArrayList<ZuulFilter>();
        // 通过注册器找到所有的过滤器(所以如果要添加过滤器需要添加到注册器中),由于注册器的代码比较简单,所以这里不做介绍
        Collection<ZuulFilter> filters = filterRegistry.getAllFilters();
        // 查找指定类型的过滤器
        for (Iterator<ZuulFilter> iterator = filters.iterator(); iterator.hasNext(); ) {
            ZuulFilter filter = iterator.next();
            if (filter.filterType().equals(filterType)) {
                // 类型相同
                list.add(filter);
            }
        }
        // 根据filterOrder排序
        Collections.sort(list); // sort by priority

        // 添加到缓存中
        hashFiltersByType.putIfAbsent(filterType, list);
        return list;
    }

【2】FilterProcessor.processZuulFilter方法介绍

 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();
            }
            // 执行过滤器
            ZuulFilterResult result = filter.runFilter();
            // 获取执行状态
            ExecutionStatus s = result.getStatus();
            // 执行时间
            execTime = System.currentTimeMillis() - ltime;

            switch (s) {
                case FAILED:
                    // 执行失败
                    t = result.getException();
                    // context中添加过滤器的执行结果
                    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");
                        // 用于记录过滤器是否添加了新的key到requestContext对象中
                        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) {
                // ZuulException
                throw (ZuulException) e;
            } else {
                // 转换为ZuulException
                ZuulException ex = new ZuulException(e, "Filter threw Exception", 500, filter.filterType() + ":" + filterName);
                // 添加过滤器执行结果
                ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime);
                throw ex;
            }
        }
    }

执行FilterProcessor.processZuulFilter的执行步骤:
(1) 记录requestContext的快照
(2) 执行真正执行过滤器
(3) 记录过滤器结果和状态,如果是执行成功,还记录requestContext增加的key
(4) 通知过滤器执行状态

现在来分析一下真正执行过滤器的逻辑,即ZuulFilter.runFilter:

ZuulFilter.java

    public ZuulFilterResult runFilter() {
        // 记录过滤器结果
        ZuulFilterResult zr = new ZuulFilterResult();
        if (!isFilterDisabled()) {
            // 过滤器有效
            if (shouldFilter()) {
                // 应该执行该过滤器

                // 开始记录轨迹
                Tracer t = TracerFactory.instance().startMicroTracer("ZUUL::" + this.getClass().getSimpleName());
                try {
                    // 运行过滤器并返回结果(新增的过滤器一定要重写这个方法)
                    Object res = run();
                    // 封装成Zuul过滤器结果对象(成功)
                    zr = new ZuulFilterResult(res, ExecutionStatus.SUCCESS);
                } catch (Throwable e) {
                    // 设置轨迹名称
                    t.setName("ZUUL::" + this.getClass().getSimpleName() + " failed");

                    // 封装成Zuul过滤器结果对象(异常)
                    zr = new ZuulFilterResult(ExecutionStatus.FAILED);
                    zr.setException(e);
                } finally {
                    // 停止轨迹记录
                    t.stopAndLog();
                }
            } else {
                // 如果不执行就表示跳过
                zr = new ZuulFilterResult(ExecutionStatus.SKIPPED);
            }
        }
        return zr;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值