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 ...
随机推荐
- Android零基础入门第66节:RecyclerView点击事件处理
前面两期学习了RecyclerView的简单使用,并为其item添加了分割线.在实际运用中,无论是List还是Grid效果,基本都会伴随着一些点击操作,那么本期就来一起学习RecyclerView的点 ...
- CopyFile函數詳解
CopyFile函數,文件拷贝函数.其基本結構如下: copyfile( lpcstr lpexistingfilename, // 源文件路径 lpcstr lpnewfilename, //新文件 ...
- 静态dll的问题终于搞定了
导入plugin,构建qapplicationhttps://forum.qt.io/topic/60940/qt-static-dll-x64-using-qapplication-issues/2 ...
- Oracle 宣布 Java 7 生命周期终结
快速使用Romanysoft LAB的技术实现 HTML 开发Mac OS App,并销售到苹果应用商店中. <HTML开发Mac OS App 视频教程> 土豆网同步更新:http: ...
- Delphi使用TObject类对象创建接受window消息(使用Classes.AllocateHWnd为对象创建一个尺寸为0的窗口,从而有了Handle)good
在delphi中,有时候我们希望对象可以接收windows消息,怎么办呢?因为要接收windows消息起码要有windows Handle,难道要建立的一个可见窗口?那样似乎太差强人意了.delphi ...
- 微信公众号开发系列-13、基于RDIFramework.NET框架整合微信开发应用效果展示
1.前言 通过前面一系列文章的学习,我们对微信公众号开发已经有了一个比较深入和全面的了解. 微信公众号开发为企业解决那些问题呢? 我们经常看到微信公众号定制开发.微信公众平台定制开发,都不知道这些能给 ...
- python之mock模块基本使用
mock简介 mock原来是python的第三方库 python3以后mock模块已经整合到了unittest测试框架中,不用再单独安装 Mock这个词在英语中有模拟的这个意思,因此我们可以猜测出这个 ...
- C语言实现常用数据结构——链表
#include<stdio.h> #include<stdlib.h> typedef struct Node { int data; struct Node *next; ...
- vue+element——父级元素fixed,遮罩会在上方
前言 这种场景还是蛮场景的 一个共用的head组件,组件里面通常是当前系统登录账号名 退出登录 修改密码这样的弹框 但是现在我又想head不跟着main内容上下滑动.所以用了fixed 定位. 问题来 ...
- 一次信号量引发的tomcat异常退出
近期在玩大数据.有个朋友找过来,说他线上的tomcat会莫名其妙的退出,表示非常苦恼,请我帮看看.每次他发现退出了,都通过腾讯云的WEB控制台登录,启动tomcat. 本着助人为乐(shao kao ...
