SpringCloud解析之Zuul(二)
本文基于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(二)的更多相关文章
- SpringCloud解析之Zuul(一)
本文基于Spring Cloud Edgware.SR6,Zuul版本1.3.1,解析Zuul的请求拦截机制,让大家对Zuul的原理有个大概的认识和了解.如有不对的地方,欢迎指正. spring bo ...
- SpringCloud学习之zuul
一.为什么要有网关 我们先看一个图,如果按照consumer and server(最初的调用方式),如下所示 这样我们要面临如下问题: 1. 用户面临着一对N的问题既用户必须知道每个服务.随着服务的 ...
- 基于SpringCloud搭建项目-Zuul篇(六)
本文主要介绍zuul的基本原理和在sprngcloud服务下如何使用 一.简单介绍 Zuul 是 Netflix OSS 中的一员,是一个基于 JVM 路由和服务端的负载均衡器.提供路由.监控.弹性. ...
- 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新
上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...
- 数据结构图文解析之:二叉堆详解及C++模板实现
0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...
- sql执行计划解析案例(二)
sql执行计划解析案例(二) 今天是2013-10-09,本来以前自己在专注oracle sga中buffer cache 以及shared pool知识点的研究.但是在研究cache buffe ...
- asp.net 生成、解析条形码和二维码
原文 asp.net 生成.解析条形码和二维码 一.条形码 一维码,俗称条形码,广泛的用于电子工业等行业.比如我们常见的书籍背面就会有条形码,通过扫描枪等设备扫描就可以获得书籍的ISBN(Intern ...
- spring cloud: zuul(二): zuul的serviceId/service-id配置(微网关)
spring cloud: zuul(二): zuul的serviceId/service-id配置(微网关) zuul: routes: #路由配置表示 myroute1: #路由名一 path: ...
- springcloud 实战 网关zuul使用中遇到的相关问题
springcloud 实战 网关zuul使用中遇到的相关问题 1.网关zuul使用时,跨域问题在网关中配置pre过滤器: response.setHeader("Access-Contr ...
随机推荐
- 【Windows10 IoT开发系列】Powershell命令行实用程序
原文:[Windows10 IoT开发系列]Powershell命令行实用程序 更新帐户密码: 强烈建议你更新默认的管理员帐户密码.若要更新帐户密码,你可以发出以下命令: net user Admin ...
- MacOS X编译OpenSceneGraph
本文主要记录在MacOS X上编译OpenSceneGraph,方便日后查阅.所使用的环境如下: MacOS X 10.10 Yosemite XCode 6.3.2 CMake 3.3.0 Open ...
- Uncaught (in promise)
Uncaught (in promise) 使用es6的promise时候,有时候会出现如下错误: 这是因为,使用定义promise方法的时候,reject了,但是,在使用的地方没有用catch进行接 ...
- 转载 《我用 TypeScript 语言的七个月》
快速使用Romanysoft LAB的技术实现 HTML 开发Mac OS App,并销售到苹果应用商店中. <HTML开发Mac OS App 视频教程> 土豆网同步更新:http: ...
- Rainyday.js – Rendering Raindrops with JavaScript
Posted · Category:GPL License,Tools 直击现场 The idea behind Rainyday.js is to create a JavaScript libra ...
- 为什么API多用C而不是C++,为什么C++程序大多不使用异常
读Defective C++随笔 不尽知用兵之害者,则不能尽知用兵之利也 ——<孙子兵法> 1.为什么API多用C而不是C++以前就一直很奇怪,为什么API大都用C的方式提供,即使有C++ ...
- 修改zookeeper jvm参数
在zkServer.sh中,增加以下参数: start) echo -n "Starting zookeeper ... " if [ -f $ZOOPIDFILE ...
- .NET错误:The tag 'BusyIndicator' ('CallMethodAction')does not exist in XML namespace
将一个项目由VS2010升级为VS2012后,在确保代码无误的情况下编译程序出现以下错误提示: 解决方法:将4.0.0.0的程序集Microsoft.Expression.Interactions.及 ...
- js简单对象List自定义属性排序
简单对象List自定义属性排序 <script type="text/javascript"> var objectList = new Array(); functi ...
- 【docker学习二】CentOS7.5+Docker 镜像(容器)的使用
承接上篇:https://mp.csdn.net/postedit/82744127 上文介绍了容器与镜像的基本操作,这里总结下容器的使用. 先在官网找到一个镜像: https://hub.docke ...