十九.SpringCloud源码剖析-Zuul的执行流程

前言

在之前的章节我们详细分析了Zuul的Filter,这一章节我们来详细跟一下Zuul的执行流程


Zuul的执行流程是这样的

  • 首先请求进来会先到达ZuulController ,ZuulController把请求交给ZuulServlet去处理
  • 在ZuulServelt会调用 ZuulRunner 依次执行: init初始化,pre前置filter,route路由filter,post后置filter, error 异常filter
  • ZuulRunner通过 FilterProcessor 去执行各种Filter,FilterProcessor通过 FilterLoader 加载 各种filters
  • 执行完成之后,把结果响应给客户端

在上一章节我们分析了Zuul中的各种filter,那这一章我们来跟踪一下zuul的执行流程。那么入口肯定是我们的 ZuulServlet ,他类似于 DispatcherServlet 在请求的最前面做分发。我们来看一下他的源码

Zuul执行流程

1.ZuulController 请求入口

ZuulController 是请求的入口,把请求交给ZuulServlet去处理,ZuulServlet 类似于 DispatcherServlet 在请求的最前面做分发

public class ZuulController extends ServletWrappingController {

	public ZuulController() {	
		//1.为父类的serveltClass 做初始化,是一个 ZuulServlet
		setServletClass(ZuulServlet.class);
		setServletName("zuul");
		setSupportedMethods((String[]) null); // Allow all
	}

	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
		try {
			// We don't care about the other features of the base class, just want to
			// handle the request
			//2.请求交个父类
			return super.handleRequestInternal(request, response);
		}
		finally {
			// @see com.netflix.zuul.context.ContextLifecycleFilter.doFilter
			RequestContext.getCurrentContext().unset();
		}
	}

}

下面是它父类的源码

public class ServletWrappingController extends AbstractController implements BeanNameAware, InitializingBean, DisposableBean {
    @Nullable
    private Class<? extends Servlet> servletClass;
    @Nullable
    private String servletName;
    private Properties initParameters = new Properties();
    @Nullable
    private String beanName;
	//servletInstance 就是 ZuulServelt
    @Nullable
    private Servlet servletInstance;

   	...省略...
   	 public void afterPropertiesSet() throws Exception {
        if (this.servletClass == null) {
            throw new IllegalArgumentException("'servletClass' is required");
        } else {
            if (this.servletName == null) {
                this.servletName = this.beanName;
            }
			//1.反射,根据 servletClass 创建实例
            this.servletInstance = (Servlet)ReflectionUtils.accessibleConstructor(this.servletClass, new Class[0]).newInstance();
            this.servletInstance.init(new ServletWrappingController.DelegatingServletConfig());
        }
    }

    protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
        Assert.state(this.servletInstance != null, "No Servlet instance");
        //2.调用ZuulServelt的service方法
        this.servletInstance.service(request, response);
        return null;
    }
2.ZuulServlet 请求的分发

ZuulServelt会调用 ZuulRunner 依次执行: init初始化,pre前置filter,route路由filter,post后置filter, error 异常filter,ZuulServlet 源码如下

/**
 1.核心Zuul servlet,可初始化和协调zuulFilter执行
 * Core Zuul servlet which intializes and orchestrates zuulFilter execution
 *
 * @author Mikey Cohen
 *         Date: 12/23/11
 *         Time: 10:44 AM
 */
public class ZuulServlet extends HttpServlet {

    private static final long serialVersionUID = -3374242278843351500L;
    private ZuulRunner 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 {
        	//初始化 , 调用zuulRunner的init方法,
        	//主要是把ServletRequest请求对象设置给RequestContext上下文
            init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);

            // Marks this request as having passed through the "Zuul engine", as opposed to servlets
            // explicitly bound in web.xml, for which requests will not have the same data attached
            RequestContext context = RequestContext.getCurrentContext();
            //将此请求标记为“ Zuul引擎”,而不是servlet
            context.setZuulEngineRan();

            try {
            	//执行pre的filter
                preRoute();
            } catch (ZuulException e) {
            	//如果异常了会走 error的filter,然后再走post的filter
                error(e);
                postRoute();
                return;
            }
            try {
            	//执行route的filter
                route();
            } catch (ZuulException e) {
               //如果异常了会走 error的filter,然后再走post的filter
                error(e);
                postRoute();
                return;
            }
            try {
            	//执行post的filter
                postRoute();
            } catch (ZuulException e) {
               //如果异常了会走 error的filter,不会再走post的filter
                error(e);
                return;
            }

        } catch (Throwable e) {
            //如果异常了会走 error的filter,默认错误码500
            error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName()));
        } finally {
            RequestContext.getCurrentContext().unset();
        }
    }

    /**
     * executes "post" ZuulFilters
     *
     * @throws ZuulException
     */
     //调用zuulRunner执行 post filter
    void postRoute() throws ZuulException {
        zuulRunner.postRoute();
    }

    /**
     * executes "route" filters
     *
     * @throws ZuulException
     */
     //调用zuulRunner执行 route filter
    void route() throws ZuulException {
        zuulRunner.route();
    }

    /**
     * executes "pre" filters
     *
     * @throws ZuulException
     */
     //调用zuulRunner执行 pre filter
    void preRoute() throws ZuulException {
        zuulRunner.preRoute();
    }

    /**
     * initializes request
     *
     * @param servletRequest
     * @param servletResponse
     */
     //调用zuulRunner执行 初始化 ,主要是把servletRequest设置给ReqestContext上下文对象
     void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {
        zuulRunner.init(servletRequest, servletResponse);
    }

    /**
     * sets error context info and executes "error" filters
     *
     * @param e
     */
     //通过RequestContext设置异常
     //通过zuulRunner执行 error filter
    void error(ZuulException e) {
        RequestContext.getCurrentContext().setThrowable(e);
        zuulRunner.error();
    }

3.ZuulRunner 执行器

上面涉及到一个非常重要的类ZuulRunner所有的请求都是通过它来执行的,此类将Servlet请求和响应初始化到RequestContext中,并将FilterProcessor调用包装为preRoute(),route(),postRoute()和error()方法 ,我们看一下ZuulRunner的源码


/**
 * This class initializes servlet requests and responses into the RequestContext and wraps the FilterProcessor calls
 * to preRoute(), route(),  postRoute(), and error() methods
 *
 * @author mikey@netflix.com
 * @version 1.0
 */
public class ZuulRunner {

    private boolean bufferRequests;

    /**
     * Creates a new <code>ZuulRunner</code> instance.
     */
    public ZuulRunner() {
        this.bufferRequests = true;
    }

    /**
     *
     * @param bufferRequests - whether to wrap the ServletRequest in HttpServletRequestWrapper and buffer the body.
	在ZuulServlet中创建ZuulRunner的时候传入的配置参数 bufferRequests,
	 它决定了是否把 ServletRequest包装在HttpServletRequestWrapper中并缓冲主体。
     */
    public ZuulRunner(boolean bufferRequests) {
        this.bufferRequests = bufferRequests;
    }

    /**
     * sets HttpServlet request and HttpResponse
     设置 请求对象和响应对象到  RequestContext 中
     * @param servletRequest
     * @param servletResponse
     */
    public void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {

        RequestContext ctx = RequestContext.getCurrentContext();
        if (bufferRequests) {
			//把 ServletRequest包装在HttpServletRequestWrapper中并缓冲主体。
            ctx.setRequest(new HttpServletRequestWrapper(servletRequest));
        } else {
            ctx.setRequest(servletRequest);
        }

        ctx.setResponse(new HttpServletResponseWrapper(servletResponse));
    }

	//这里通过 FilterProcessor 执行器调用各种 ZuulFilters
    /**
     * executes "post" filterType  ZuulFilters
     *
     * @throws ZuulException
     */
    public void postRoute() throws ZuulException {
        FilterProcessor.getInstance().postRoute();
    }

    /**
     * executes "route" filterType  ZuulFilters
     *
     * @throws ZuulException
     */
    public void route() throws ZuulException {
        FilterProcessor.getInstance().route();
    }

    /**
     * executes "pre" filterType  ZuulFilters
     *
     * @throws ZuulException
     */
    public void preRoute() throws ZuulException {
        FilterProcessor.getInstance().preRoute();
    }

    /**
     * executes "error" filterType  ZuulFilters
     */
    public void error() {
        FilterProcessor.getInstance().error();
    }
4.FilterProcessor filter执行器

继续跟踪一下 FilterProcessor的源码

public class FilterProcessor {
  ...省略代码...
  /**
     * runs "post" filters which are called after "route" filters. ZuulExceptions from ZuulFilters are thrown.
     * Any other Throwables are caught and a ZuulException is thrown out with a 500 status code
     *
     * @throws ZuulException
     */
    public void postRoute() throws ZuulException {
        try {
        	//执行 post 类型的filter
            runFilters("post");
        } catch (ZuulException e) {
            throw e;
        } catch (Throwable e) {
            throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_POST_FILTER_" + e.getClass().getName());
        }
    }

    /**
     * runs all "error" filters. These are called only if an exception occurs. Exceptions from this are swallowed and logged so as not to bubble up.
     */
    public void error() {
        try {
        	//执行 error 类型的filter
            runFilters("error");
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * Runs all "route" filters. These filters route calls to an origin.
     *
     * @throws ZuulException if an exception occurs.
     */
    public void route() throws ZuulException {
        try {
        	//执行 post 类型的filter
            runFilters("post");
        } catch (ZuulException e) {
            throw e;
        } catch (Throwable e) {
            throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_ROUTE_FILTER_" + e.getClass().getName());
        }
    }

    /**
     * runs all "pre" filters. These filters are run before routing to the orgin.
     *
     * @throws ZuulException
     */
    public void preRoute() throws ZuulException {
        try {
        	//执行 pre 类型的filter
            runFilters("pre");
        } catch (ZuulException e) {
            throw e;
        } catch (Throwable e) {
            throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_PRE_FILTER_" + e.getClass().getName());
        }
    }

    /**
    
     * runs all filters of the filterType sType/ Use this method within filters to run custom filters by type
     *
     * @param sType the filterType.
     * @return
     * @throws Throwable throws up an arbitrary exception
     */
     //执行Filter的核心方法,运行所有过滤器/在过滤器中使用此方法可按类型运行自定义过滤器
    public Object runFilters(String sType) throws Throwable {
        if (RequestContext.getCurrentContext().debugRouting()) {
            Debug.addRoutingDebug("Invoking {" + sType + "} type filters");
        }
        boolean bResult = false;
        //通过 FilterLoader 加载 filters
        List<ZuulFilter> list = FilterLoader.getInstance().getFiltersByType(sType);
        if (list != null) {
            for (int i = 0; i < list.size(); i++) {
                ZuulFilter zuulFilter = list.get(i);
                //拿到每个filter,调用 processZuulFilter 去执行
                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
     */
     //filter的执行方法
    public Object processZuulFilter(ZuulFilter filter) throws ZuulException {

        RequestContext ctx = RequestContext.getCurrentContext();
        //获取时候开启:debug
        boolean bDebug = ctx.debugRouting();
        final String metricPrefix = "zuul.filter-";
        long execTime = 0;
        String filterName = "";
        try {
            long ltime = System.currentTimeMillis();
            //filter的类名
            
            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.runFilter方法真正执行Filter
            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;
            }
        }
    }
...省略代码...

不管是前置,后置,路由,异常的Filter ,FilterProcessor 都通过 runFilters("类型"); 方法去执行filter,方法中通过 FilterLoader加载指定类型的Filter列表,然后交给 processZuulFilter方法去执行 ,该方法最终调用ZuulFilter.runFilter();方法去执行具体的Filter 。它会以下面的顺序去执行内置的Filter:

类型过滤器描述顺序
preServletDetectionFilter在pre过滤器中,ServletDetectionFilter是第一个执行的过滤器,检测请求是用 DispatcherServlet还是 ZuulServlet,将结果设置到RequestContext中-3
preServlet30WrapperFilter主要是将原始请求进行包装,将原始的HttpServletRequest请求包装成Servlet30RequestWrapper类型-2
preFormBodyWrapperFilter同Servlet30RequestWrapper一样,也是对请求的一个包装,只不过他只包装表单数据,即:content-type中必须带有“application/x-www-form-urlencoded”或“multipart/form-data”-1
errorSendErrorFilter这个是用来发送错误的Filter0
preDebugFilter设置请求过程是否开启debug,将当前请求上下文中的debugRoutingdebugRequest参数设置为true1
prePreDecorationFilter基本的路由转发配置,根据uri调用哪一个route过滤器5
routeRibbonRoutingFilter服务路由的过滤器,使用用Ribbon 做负载均衡,hystrix做熔断10
routeSimpleHostRoutingFilter简单主机路由过滤器,如果使用url路由,则用这个过滤器100
routeSendForwardFilter它使用RequestDispatcher转发请求500
postSendResponseFilterSendResponseFilter是Zuul的最后一个Filter,负责最终响应结果的输出。1000

error类型的filter在出异常的时候才会执行

5.ZuulFilter

ZuulFilter 是所有Filter的抽象类,它的接口是IZuulFilter ,它里面有四个很重要的方法

//这个是
public interface IZuulFilter {
	//是否要执行Run方法
    boolean shouldFilter();
	//filter的核心业务方法
    Object run() throws ZuulException;
}

public abstract class ZuulFilter implements IZuulFilter, Comparable<ZuulFilter> {

    private final AtomicReference<DynamicBooleanProperty> filterDisabledRef = new AtomicReference<>();

    /**
     * to classify a filter by type. Standard types in Zuul are "pre" for pre-routing filtering,
     * "route" for routing to an origin, "post" for post-routing filters, "error" for error handling.
     * We also support a "static" type for static responses see  StaticResponseFilter.
     * Any filterType made be created or added and run by calling FilterProcessor.runFilters(type)
     *
     * @return A String representing that type
     */
     //这个是filter的类型 ,有 pre ,route,post error
    abstract public String filterType();

    /**
     * filterOrder() must also be defined for a filter. Filters may have the same  filterOrder if precedence is not
     * important for a filter. filterOrders do not need to be sequential.
     *
     * @return the int order of a filter
     */
     //这个是filter的执行顺序,越小越先执行
    abstract public int filterOrder();
    ...省略...
}

详细看一下ZuulFilter 的源码

public abstract class ZuulFilter implements IZuulFilter, Comparable<ZuulFilter> {
...省略...
 public ZuulFilterResult runFilter() {
        ZuulFilterResult zr = new ZuulFilterResult();
        if (!isFilterDisabled()) {
        	//调用shouldFilter方法,这是个抽象方法,子类需要复写该方法返回 bool值决定要不要执行run方法
            if (shouldFilter()) {
                Tracer t = TracerFactory.instance().startMicroTracer("ZUUL::" + this.getClass().getSimpleName());
                try {
             		 //调用 filter的run方法去执行,也是个抽象方法,需要子类去实现自己的业务逻辑
                    Object res = run();
                    //执行成功,包装一个成功状态的ZuulFilterResult对象返回
                    zr = new ZuulFilterResult(res, ExecutionStatus.SUCCESS);
                } catch (Throwable e) {
                    t.setName("ZUUL::" + this.getClass().getSimpleName() + " failed");
                    //执行失败,包装一个失败状态的ZuulFilterResult对象返回
                    zr = new ZuulFilterResult(ExecutionStatus.FAILED);
                    zr.setException(e);
                } finally {
                    t.stopAndLog();
                }
            } else {
                zr = new ZuulFilterResult(ExecutionStatus.SKIPPED);
            }
        }
        return zr;
    }

ZuulFilter 是个抽象类,需要具体的子类类去复写其中的四个方法,然后 ZuulFilter 做的事情就依次调用 shouldFilter 方法,如果返回true就调用 run方法执行子类的业务逻辑,然后把结果封装成ZuulFilterResult返回。

到这里Zuul的执行流程的跟踪就算结束了,剩下的就是具体的Filter本身的业务代码的理解了,Zuul通过依次调用这个写Filter来完成整个生命周期的执行。最后总结一下流程

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

墨家巨子@俏如来

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值