本文基于Spring Cloud Edgware.SR6,Zuul版本1.3.1,解析Zuul的请求拦截机制,让大家对Zuul的原理有个大概的认识和了解。如有不对的地方,欢迎指正。

在上一期的SpringCloud解析之Zuul(一),我们了解了spring boot在接收一个网关请求后,是如何找到与之匹配的ZuulHandlerMapping。今天我们继续探寻,这个ZuulHandlerMapping是如何处理网关请求的。

在开始之前,我们先了解一下,为什么spring boot要如此大费周章的,只为找到ZuulHandlerMapping。

通过上一期文章,我们知道所有的浏览器请求都会到达DispatcherServlet,并且DispatcherServlet中有一个成员变量handlerMappings,会扫描所有继承HandlerMapping接口的实现类,其实它里面还有一个成员变量handlerAdapters,这个变量会扫描所有HandlerAdapter接口的实现类。从名字命名上可以看出,handlerAdapters包含了所有的处理器适配器,所有的HandlerMapping都会通过其对应的HandlerAdapter来执行,目的是为了解耦。因为这样设计之后,DispatcherServlet和HandlerMapping都不会包含特定的逻辑代码,也不需要关心是什么类型的请求,只需要调用对应的HandlerAdapter的方法就可以了。

ZuulHandlerMapping里面有什么呢?ZuulHandlerMapping中有一个成员变量ZuulController,ZuulController继承了ServletWrappingController,ServletWrappingController中有servletClass和servletInstance。

在上一期开头,我粗略的提及,在spring boot启动过程中会初始化ZuulController,继而通过反射初始化ZuulServlet。详细的说,是spring boot启动过程中会通过org.springframework.cloud.netflix.zuul.ZuulServerAutoConfiguration自动配置类来初始化zuul,其中包括ZuulHandlerMapping。所以,ZuulHandlerMapping中有ZuulController,ZuulController中有ZuulServlet,这些对象实例在spring boot启动成功后就有了。

好,在了解了这些之后,我们继续今天的内容。DispatcherServlet.doDispatch()在获取到ZuulHandlerMapping之后,马上调用方法getHandlerAdapter()获取对应的HandlerAdapter。

可以看到,getHandlerAdapter()内部是在遍历handlerAdapters,然后通过调用各自的supports()方法判断哪一个handlerAdapter支持前面获取的handler处理器。这里取到的是SimpleControllerHandlerAdapter。

取到handlerAdapter之后,开始调用handlerAdapter的handle()方法,mappedHandler.getHandler()就是ZuulController。SimpleControllerHandlerAdapter.handle()内部,是ZuulController.handleRequest(),其内部又是调用父类的handleRequestInternal(),真正起作用的是servletInstance.service(),而servletInstance正是ZuulServlet(我们开头讲到的)

下面我们看下,ZuulServlet.service()做了什么。

public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {
try {
// 初始化,将servletRequest和servletResponse存储到请求上下文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();
context.setZuulEngineRan();
// 顺序执行ZuulFilter过滤器,也包括我们继承ZuulFilter的自定义过滤器
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();
}
}

简直一目了然。我们往下看,它是如何会执行我们继承ZuulFilter的自定义过滤器。(上文忘了说,在ZuulServlet实例化后,会调用init()方法初始化ZuulRunner)。

以preRoute()为例,不难看出,最终的执行者是FilterProcessor,在runFilters()方法中,获取对应类型的List<ZuulFilter>,然后遍历执行processZuulFilter(zuulFilter)

FilterLoader.getInstance().getFiltersByType(sType)内容如下,就是从hashFiltersByType中获取filterType对应的List<ZuulFilter>

那么新问题就来了,hashFiltersByType里的值怎么来的。FilterLoader还有一个putFilter(File file)方法,通过查找源码很容易发现,这个方法是在FilterFileManager中被调用的。官方的解释是,FilterFileManager类负责初始化和更新filter(但是我一直搞不懂它是如何调用运行的,因为我打断点都没有效果,猜测是Groovy,不甚了解,知道的小伙伴帮忙评论解释下,感激不尽)。

INSTANCE.manageFiles()最终调用的就是FilterLoader.putFilter()方法,INSTANCE.startPoller()则是启动一个守护线程,轮询执行manageFiles()。

回过头来,我们继续看processZuulFilter(zuulFilter)干了什么。额,其实关键就下面一句,

ZuulFilter.runFilter()方法,首先判断!isFilterDisabled(),shouldFilter(),同时满足时才执行run()方法,即配置文件中isFilter没有禁用,并且自定义过滤器的shouldFilter()返回true,才会执行重写ZuulFilter的run()方法。

至此,zuul网关执行过滤器和自定义过滤器的过程就讲完了(啊,累死了)。

最后,总结一下:

1.spring boot通过适配器设计模式,使用对应的HandlerAdapter来执行ZuulHandlerMapping,以达到解耦的目的。而ZuulHandlerMapping最终是调用的ZuulServlet.service()

2.ZuulServlet.service()里面,也是取出filterType类型的所有ZuulFilter,然后遍历执行ZuulFilter的run()方法,这也是为什么我们写自定义过滤器要继承ZuulFilter的原因。

下一期,我们来聊聊Zuul对请求过滤处理后,是如何将请求转发到对应的服务器的。

SpringCloud解析之Zuul(二)的更多相关文章

  1. SpringCloud解析之Zuul(一)

    本文基于Spring Cloud Edgware.SR6,Zuul版本1.3.1,解析Zuul的请求拦截机制,让大家对Zuul的原理有个大概的认识和了解.如有不对的地方,欢迎指正. spring bo ...

  2. SpringCloud学习之zuul

    一.为什么要有网关 我们先看一个图,如果按照consumer and server(最初的调用方式),如下所示 这样我们要面临如下问题: 1. 用户面临着一对N的问题既用户必须知道每个服务.随着服务的 ...

  3. 基于SpringCloud搭建项目-Zuul篇(六)

    本文主要介绍zuul的基本原理和在sprngcloud服务下如何使用 一.简单介绍 Zuul 是 Netflix OSS 中的一员,是一个基于 JVM 路由和服务端的负载均衡器.提供路由.监控.弹性. ...

  4. 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新

    上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...

  5. 数据结构图文解析之:二叉堆详解及C++模板实现

    0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...

  6. sql执行计划解析案例(二)

    sql执行计划解析案例(二)   今天是2013-10-09,本来以前自己在专注oracle sga中buffer cache 以及shared pool知识点的研究.但是在研究cache buffe ...

  7. asp.net 生成、解析条形码和二维码

    原文 asp.net 生成.解析条形码和二维码 一.条形码 一维码,俗称条形码,广泛的用于电子工业等行业.比如我们常见的书籍背面就会有条形码,通过扫描枪等设备扫描就可以获得书籍的ISBN(Intern ...

  8. spring cloud: zuul(二): zuul的serviceId/service-id配置(微网关)

    spring cloud: zuul(二): zuul的serviceId/service-id配置(微网关) zuul: routes: #路由配置表示 myroute1: #路由名一 path: ...

  9. springcloud 实战 网关zuul使用中遇到的相关问题

    springcloud 实战  网关zuul使用中遇到的相关问题 1.网关zuul使用时,跨域问题在网关中配置pre过滤器: response.setHeader("Access-Contr ...

随机推荐

  1. MyCat的初步了解

    MyCat 1 开源数据库中间件 MyCat   如今随着互联网的发展,数据的量级也是撑指数的增长,从GB到TB到PB.对数据的各种操作也是愈加的困难,传统的关系性数据库已经无法满足快速查询与插入数据 ...

  2. redis的简介和使用

    简介 redis(Remote Dictionary Server)是一种Nosql技术,它是一个开源的高级kv存储和数据结构存储系统,它经常被拿来和Memcached相比较,但是Memcached不 ...

  3. 高启全:长江存储自主3D NAND,DRAM研发欢迎美光一起加入(千秋大业,慢慢做)

    台湾DRAM教父高启全转战大陆紫光集团操盘存储器大计划超过1年,日前晋升长江存储的执行董事.代行董事长,接受DIGITIMES独家专访公开未来规划:他指出,已齐聚500名研发人员在武汉投入3D NAN ...

  4. 演练:创建和使用动态链接库 (C++)

    我们将创建的第一种类型的库是动态链接库 (DLL). 使用 DLL 是一种重用代码的绝佳方式. 您不必在自己创建的每个程序中重新实现同一例程,而只需对这些例程编写一次,然后从需要该功能的应用程序引用它 ...

  5. Google C++测试框架系列高级篇:第一章 更多关于断言的知识

    原始链接:More Assertions 词汇表 现在你应该已经读完了入门篇并且会使用GTest来写测试.是时候来学一些新把戏了.这篇文档将教会你更多知识:用断言构造复杂的失败信息,传递致命失败,重用 ...

  6. 血的教训--如何正确使用线程池submit和execute方法

    血的教训之背景:使用线程池对存量数据进行迁移,但是总有一批数据迁移失败,无异常日志打印 凶案起因 ​ 听说parallelStream并行流是个好东西,由于日常开发stream串行流的场景比较多,这次 ...

  7. Laravel --- 部署Laravel项目到vps主要步骤以及遇到的问题记录

    买了一个国外的vps,然后搭建环境并且跑了下laravel,折腾了一天半左右,遇到的问题和操作在此记录下: 1.我把本地的代码用git方式上传到github,然后在vps用git下载代码,步骤如下 - ...

  8. spring 5.x 系列第9篇 —— 整合mongodb (xml配置方式)

    源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.说明 1.1 项目结构说明 配置文件位于resources下,项目以单 ...

  9. 用arduino制作具有无限数据传输功能的气象站

    本项目是用arduino开源硬件,来快速制作具有无限数据传输功能的气象站,我之前做过一个带数据记录功能的气象站项目,这次算是升级和改进的版本. 第1步:构想 首先,需要增加从气象站到室内接收器的无线数 ...

  10. JavaWeb入门_模仿天猫整站Tmall_SSM实践项目

    Tmall_SSM 技术栈 Spring MVC+ Mybatis + Spring + Jsp + Tomcat , 是 Java Web 入门非常好的练手项目 效果展示: 模仿天猫前台 模仿天猫后 ...