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

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

前言

在之前的章节我们详细分析了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 在请求的最前面做分发

publicclassZuulControllerextendsServletWrappingController {
publicZuulController() {   
//1.为父类的serveltClass 做初始化,是一个 ZuulServletsetServletClass(ZuulServlet.class);
setServletName("zuul");
setSupportedMethods((String[]) null); // Allow all    }
@OverridepublicModelAndViewhandleRequest(HttpServletRequestrequest, HttpServletResponseresponse) throwsException {
try {
// We don't care about the other features of the base class, just want to// handle the request//2.请求交个父类returnsuper.handleRequestInternal(request, response);
        }
finally {
// @see com.netflix.zuul.context.ContextLifecycleFilter.doFilterRequestContext.getCurrentContext().unset();
        }
    }
}

下面是它父类的源码

publicclassServletWrappingControllerextendsAbstractControllerimplementsBeanNameAware, InitializingBean, DisposableBean {
@NullableprivateClass<?extendsServlet>servletClass;
@NullableprivateStringservletName;
privatePropertiesinitParameters=newProperties();
@NullableprivateStringbeanName;
//servletInstance 就是 ZuulServelt@NullableprivateServletservletInstance;
    ...省略...
publicvoidafterPropertiesSet() throwsException {
if (this.servletClass==null) {
thrownewIllegalArgumentException("'servletClass' is required");
        } else {
if (this.servletName==null) {
this.servletName=this.beanName;
            }
//1.反射,根据 servletClass 创建实例this.servletInstance= (Servlet)ReflectionUtils.accessibleConstructor(this.servletClass, newClass[0]).newInstance();
this.servletInstance.init(newServletWrappingController.DelegatingServletConfig());
        }
    }
protectedModelAndViewhandleRequestInternal(HttpServletRequestrequest, HttpServletResponseresponse) throwsException {
Assert.state(this.servletInstance!=null, "No Servlet instance");
//2.调用ZuulServelt的service方法this.servletInstance.service(request, response);
returnnull;
    }
}   

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*/publicclassZuulServletextendsHttpServlet {
privatestaticfinallongserialVersionUID=-3374242278843351500L;
privateZuulRunnerzuulRunner;
//初始化 ZuulRunner @Overridepublicvoidinit(ServletConfigconfig) throwsServletException {
super.init(config);
StringbufferReqsStr=config.getInitParameter("buffer-requests");
booleanbufferReqs=bufferReqsStr!=null&&bufferReqsStr.equals("true") ?true : false;
zuulRunner=newZuulRunner(bufferReqs);
    }
//请求执行核心方法@Overridepublicvoidservice(javax.servlet.ServletRequestservletRequest, javax.servlet.ServletResponseservletResponse) throwsServletException, 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 attachedRequestContextcontext=RequestContext.getCurrentContext();
//将此请求标记为“ Zuul引擎”,而不是servletcontext.setZuulEngineRan();
try {
//执行pre的filterpreRoute();
            } catch (ZuulExceptione) {
//如果异常了会走 error的filter,然后再走post的filtererror(e);
postRoute();
return;
            }
try {
//执行route的filterroute();
            } catch (ZuulExceptione) {
//如果异常了会走 error的filter,然后再走post的filtererror(e);
postRoute();
return;
            }
try {
//执行post的filterpostRoute();
            } catch (ZuulExceptione) {
//如果异常了会走 error的filter,不会再走post的filtererror(e);
return;
            }
        } catch (Throwablee) {
//如果异常了会走 error的filter,默认错误码500error(newZuulException(e, 500, "UNHANDLED_EXCEPTION_"+e.getClass().getName()));
        } finally {
RequestContext.getCurrentContext().unset();
        }
    }
/*** executes "post" ZuulFilters** @throws ZuulException*///调用zuulRunner执行 post filtervoidpostRoute() throwsZuulException {
zuulRunner.postRoute();
    }
/*** executes "route" filters** @throws ZuulException*///调用zuulRunner执行 route filtervoidroute() throwsZuulException {
zuulRunner.route();
    }
/*** executes "pre" filters** @throws ZuulException*///调用zuulRunner执行 pre filtervoidpreRoute() throwsZuulException {
zuulRunner.preRoute();
    }
/*** initializes request** @param servletRequest* @param servletResponse*///调用zuulRunner执行 初始化 ,主要是把servletRequest设置给ReqestContext上下文对象voidinit(HttpServletRequestservletRequest, HttpServletResponseservletResponse) {
zuulRunner.init(servletRequest, servletResponse);
    }
/*** sets error context info and executes "error" filters** @param e*///通过RequestContext设置异常//通过zuulRunner执行 error filtervoiderror(ZuulExceptione) {
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*/publicclassZuulRunner {
privatebooleanbufferRequests;
/*** Creates a new <code>ZuulRunner</code> instance.*/publicZuulRunner() {
this.bufferRequests=true;
    }
/**** @param bufferRequests - whether to wrap the ServletRequest in HttpServletRequestWrapper and buffer the body.在ZuulServlet中创建ZuulRunner的时候传入的配置参数 bufferRequests,它决定了是否把 ServletRequest包装在HttpServletRequestWrapper中并缓冲主体。*/publicZuulRunner(booleanbufferRequests) {
this.bufferRequests=bufferRequests;
    }
/*** sets HttpServlet request and HttpResponse设置 请求对象和响应对象到  RequestContext 中* @param servletRequest* @param servletResponse*/publicvoidinit(HttpServletRequestservletRequest, HttpServletResponseservletResponse) {
RequestContextctx=RequestContext.getCurrentContext();
if (bufferRequests) {
//把 ServletRequest包装在HttpServletRequestWrapper中并缓冲主体。ctx.setRequest(newHttpServletRequestWrapper(servletRequest));
        } else {
ctx.setRequest(servletRequest);
        }
ctx.setResponse(newHttpServletResponseWrapper(servletResponse));
    }
//这里通过 FilterProcessor 执行器调用各种 ZuulFilters/*** executes "post" filterType  ZuulFilters** @throws ZuulException*/publicvoidpostRoute() throwsZuulException {
FilterProcessor.getInstance().postRoute();
    }
/*** executes "route" filterType  ZuulFilters** @throws ZuulException*/publicvoidroute() throwsZuulException {
FilterProcessor.getInstance().route();
    }
/*** executes "pre" filterType  ZuulFilters** @throws ZuulException*/publicvoidpreRoute() throwsZuulException {
FilterProcessor.getInstance().preRoute();
    }
/*** executes "error" filterType  ZuulFilters*/publicvoiderror() {
FilterProcessor.getInstance().error();
    }
}

4.FilterProcessor filter执行器

继续跟踪一下 FilterProcessor的源码

publicclassFilterProcessor {
  ...省略代码...
/*** 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*/publicvoidpostRoute() throwsZuulException {
try {
//执行 post 类型的filterrunFilters("post");
        } catch (ZuulExceptione) {
throwe;
        } catch (Throwablee) {
thrownewZuulException(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.*/publicvoiderror() {
try {
//执行 error 类型的filterrunFilters("error");
        } catch (Throwablee) {
logger.error(e.getMessage(), e);
        }
    }
/*** Runs all "route" filters. These filters route calls to an origin.** @throws ZuulException if an exception occurs.*/publicvoidroute() throwsZuulException {
try {
//执行 post 类型的filterrunFilters("post");
        } catch (ZuulExceptione) {
throwe;
        } catch (Throwablee) {
thrownewZuulException(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*/publicvoidpreRoute() throwsZuulException {
try {
//执行 pre 类型的filterrunFilters("pre");
        } catch (ZuulExceptione) {
throwe;
        } catch (Throwablee) {
thrownewZuulException(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的核心方法,运行所有过滤器/在过滤器中使用此方法可按类型运行自定义过滤器publicObjectrunFilters(StringsType) throwsThrowable {
if (RequestContext.getCurrentContext().debugRouting()) {
Debug.addRoutingDebug("Invoking {"+sType+"} type filters");
        }
booleanbResult=false;
//通过 FilterLoader 加载 filtersList<ZuulFilter>list=FilterLoader.getInstance().getFiltersByType(sType);
if (list!=null) {
for (inti=0; i<list.size(); i++) {
ZuulFilterzuulFilter=list.get(i);
//拿到每个filter,调用 processZuulFilter 去执行Objectresult=processZuulFilter(zuulFilter);
if (result!=null&&resultinstanceofBoolean) {
bResult|= ((Boolean) result);
                }
            }
        }
//返回结果returnbResult;
    }
/*** 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的执行方法publicObjectprocessZuulFilter(ZuulFilterfilter) throwsZuulException {
RequestContextctx=RequestContext.getCurrentContext();
//获取时候开启:debugbooleanbDebug=ctx.debugRouting();
finalStringmetricPrefix="zuul.filter-";
longexecTime=0;
StringfilterName="";
try {
longltime=System.currentTimeMillis();
//filter的类名filterName=filter.getClass().getSimpleName();
RequestContextcopy=null;
Objecto=null;
Throwablet=null;
if (bDebug) {
Debug.addRoutingDebug("Filter "+filter.filterType() +" "+filter.filterOrder() +" "+filterName);
copy=ctx.copy();
            }
//【重要】调用 ZuulFilter.runFilter方法真正执行FilterZuulFilterResultresult=filter.runFilter();
//拿到响应状态ExecutionStatuss=result.getStatus();
execTime=System.currentTimeMillis() -ltime;
switch (s) {
//执行失败caseFAILED:
t=result.getException();
//将过滤器名称和状态附加到当前请求的过滤器执行历史记录中ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime);
break;
//执行成功caseSUCCESS:
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) throwt;
usageNotifier.notify(filter, s);
returno;
        } catch (Throwablee) {
if (bDebug) {
Debug.addRoutingDebug("Running Filter failed "+filterName+" type:"+filter.filterType() +" order:"+filter.filterOrder() +" "+e.getMessage());
            }
usageNotifier.notify(filter, ExecutionStatus.FAILED);
if (einstanceofZuulException) {
throw (ZuulException) e;
            } else {
ZuulExceptionex=newZuulException(e, "Filter threw Exception", 500, filter.filterType() +":"+filterName);
ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime);
throwex;
            }
        }
    }
...省略代码...

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

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

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

5.ZuulFilter

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

//这个是publicinterfaceIZuulFilter {
//是否要执行Run方法booleanshouldFilter();
//filter的核心业务方法Objectrun() throwsZuulException;
}
publicabstractclassZuulFilterimplementsIZuulFilter, Comparable<ZuulFilter> {
privatefinalAtomicReference<DynamicBooleanProperty>filterDisabledRef=newAtomicReference<>();
/*** 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 errorabstractpublicStringfilterType();
/*** 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的执行顺序,越小越先执行abstractpublicintfilterOrder();
    ...省略...
}

详细看一下ZuulFilter 的源码

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

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

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

目录
相关文章
|
19天前
|
Java 应用服务中间件 Nacos
Spring Cloud 常用各个组件详解及实现原理(附加源码+实现逻辑图)
Spring Cloud 常用各个组件详解及实现原理(附加源码+实现逻辑图)
31 0
|
2月前
|
SpringCloudAlibaba Java 持续交付
【构建一套Spring Cloud项目的大概步骤】&【Springcloud Alibaba微服务分布式架构学习资料】
【构建一套Spring Cloud项目的大概步骤】&【Springcloud Alibaba微服务分布式架构学习资料】
191 0
|
2月前
|
SpringCloudAlibaba Java 网络架构
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(七)Spring Cloud Gateway服务网关
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(七)Spring Cloud Gateway服务网关
117 0
|
18天前
|
Java Nacos 开发者
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
|
23天前
|
Java Maven Nacos
Spring Cloud Eureka 服务注册和服务发现超详细(附加--源码实现案例--及实现逻辑图)
Spring Cloud Eureka 服务注册和服务发现超详细(附加--源码实现案例--及实现逻辑图)
31 0
|
24天前
|
人工智能 监控 安全
Java+Spring Cloud +Vue+UniApp微服务智慧工地云平台源码
视频监控系统、人员实名制与分账制管理系统、车辆管理系统、环境监测系统、大型设备监测(龙门吊、塔吊、升降机、卸料平台等)、用电监测系统、基坑监测系统、AI算法分析(安全帽佩戴、火焰识别、周界报警、人员聚众报警、升降机超载报警)、安全培训、设备监测。
28 4
|
25天前
|
人工智能 监控 安全
Spring Cloud+Uniapp 智慧工地云平台源码 智慧工地云平台AI视频分析应用
AI视频分析包括行为分析,即人员安全帽佩戴检测、反光衣穿戴检测、人员出入检测、区域入侵监测,以及烟火监测、人数统计、人脸识别、车辆识别、人体测温等。
17 0
|
28天前
|
人工智能 监控 安全
Springcloud数字化物联网智慧工地综合平台源码 劳务管理、设备管理、绿色施工
Springcloud数字化物联网智慧工地综合平台源码 劳务管理、设备管理、绿色施工
42 3
|
1月前
|
传感器 数据采集 监控
基于Springcloud可视化项目:智慧工地可视化大数据云平台源码
终端层,充分利用物联网技术和移动应用提高现场管控能力。通过传感器、摄像头等终端设备,实现对项目建设过程的实时监控、智能感知、数据采集和高效协同,提高作业现场的管理能力。
31 5
|
1月前
|
开发框架 负载均衡 Java
Spring boot与Spring cloud之间的关系
总之,Spring Boot和Spring Cloud之间的关系是一种构建和扩展的关系,Spring Boot提供了基础,而Spring Cloud在此基础上提供了分布式系统和微服务架构所需的扩展和工具。
22 4
Spring boot与Spring cloud之间的关系