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来完成整个生命周期的执行。最后总结一下流程

目录
相关文章
|
2月前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
410 37
|
2月前
|
负载均衡 Java 网络架构
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
102 5
|
3月前
|
人工智能 前端开发 Java
【实操】Spring Cloud Alibaba AI,阿里AI这不得玩一下(含前后端源码)
本文介绍了如何使用 **Spring Cloud Alibaba AI** 构建基于 Spring Boot 和 uni-app 的聊天机器人应用。主要内容包括:Spring Cloud Alibaba AI 的概念与功能,使用前的准备工作(如 JDK 17+、Spring Boot 3.0+ 及通义 API-KEY),详细实操步骤(涵盖前后端开发工具、组件选择、功能分析及关键代码示例)。最终展示了如何成功实现具备基本聊天功能的 AI 应用,帮助读者快速搭建智能聊天系统并探索更多高级功能。
1350 2
【实操】Spring Cloud Alibaba AI,阿里AI这不得玩一下(含前后端源码)
|
1月前
|
负载均衡 Java API
【Spring Cloud生态】Spring Cloud Gateway基本配置
【Spring Cloud生态】Spring Cloud Gateway基本配置
37 0
|
3月前
|
Java Spring
【Azure Spring Cloud】Spring Cloud Azure 4.0 调用Key Vault遇见认证错误 AADSTS90002: Tenant not found.
【Azure Spring Cloud】Spring Cloud Azure 4.0 调用Key Vault遇见认证错误 AADSTS90002: Tenant not found.
|
3月前
|
Java Spring 容器
【Azure Spring Cloud】在Azure Spring Apps上看见 App Memory Usage 和 jvm.menory.use 的指标的疑问及OOM
【Azure Spring Cloud】在Azure Spring Apps上看见 App Memory Usage 和 jvm.menory.use 的指标的疑问及OOM
|
3月前
|
存储 Java Spring
【Azure Spring Cloud】Azure Spring Cloud服务,如何获取应用程序日志文件呢?
【Azure Spring Cloud】Azure Spring Cloud服务,如何获取应用程序日志文件呢?
|
3月前
|
SQL Java 数据库连接
【Azure Spring Cloud】Azure Spring Cloud connect to SQL using MSI
【Azure Spring Cloud】Azure Spring Cloud connect to SQL using MSI
|
3月前
|
Java 开发工具 Spring
【Azure Spring Cloud】使用azure-spring-boot-starter-storage来上传文件报错: java.net.UnknownHostException: xxxxxxxx.blob.core.windows.net: Name or service not known
【Azure Spring Cloud】使用azure-spring-boot-starter-storage来上传文件报错: java.net.UnknownHostException: xxxxxxxx.blob.core.windows.net: Name or service not known
|
3月前
|
NoSQL Java Redis
【Azure Spring Cloud】Java Spring Cloud 应用部署到Azure上后,发现大量的 java.lang.NullPointerException: null at io.lettuce.core.protocol.CommandHandler.writeSingleCommand(CommandHandler.java:426) at ... 异常
【Azure Spring Cloud】Java Spring Cloud 应用部署到Azure上后,发现大量的 java.lang.NullPointerException: null at io.lettuce.core.protocol.CommandHandler.writeSingleCommand(CommandHandler.java:426) at ... 异常