beaninfo详解源码解析 java_Java后端精选技术:源码解析Spring Cloud Zuul

Zuul 架构图

2f8be81a9f9950f61b395b7f93959c93.png

在zuul中, 整个请求的过程是这样的,首先将请求给zuulservlet处理,zuulservlet中有一个zuulRunner对象,该对象中初始化了RequestContext:作为存储整个请求的一些数据,并被所有的zuulfilter共享。zuulRunner中还有 FilterProcessor,FilterProcessor作为执行所有的zuulfilter的管理器。FilterProcessor从filterloader 中获取zuulfilter,而zuulfilter是被filterFileManager所加载,并支持groovy热加载,采用了轮询的方式热加载。有了这些filter之后,zuulservelet首先执行的Pre类型的过滤器,再执行route类型的过滤器,最后执行的是post 类型的过滤器,如果在执行这些过滤器有错误的时候则会执行error类型的过滤器。执行完这些过滤器,最终将请求的结果返回给客户端。

zuul工作原理源码分析

在之前已经讲过,如何使用zuul,其中不可缺少的一个步骤就是在程序的启动类加上@EnableZuulProxy,该EnableZuulProxy类代码如下:

073ac1efdec403311ac354e66e20ec22.png

其中,引用了ZuulProxyConfiguration,跟踪ZuulProxyConfiguration,该类注入了DiscoveryClient、RibbonCommandFactoryConfiguration用作负载均衡相关的。注入了一些列的filters,比如PreDecorationFilter、RibbonRoutingFilter、SimpleHostRoutingFilter,代码如如下:

97eb0a89ba3db4ef1c992b10b7fcf129.png

它的父类ZuulConfiguration ,引用了一些相关的配置。在缺失zuulServlet bean的情况下注入了ZuulServlet,该类是zuul的核心类。

cf540703a5bf6234b5d78cc226667f3b.png

同时也注入了其他的过滤器,比如ServletDetectionFilter、DebugFilter、Servlet30WrapperFilter,这些过滤器都是pre类型的。

114d441cc98e4e05e3c519290cc1aa15.png

它也注入了post类型的,比如 SendResponseFilter,error类型,比如 SendErrorFilter,route类型比如SendForwardFilter,代码如下:

d3131c3a658cec6472732c802e370698.png

初始化ZuulFilterInitializer类,将所有的filter 向FilterRegistry注册。

8f898a3d193bd12a119a7e8ee09f7a04.png

而FilterRegistry管理了一个ConcurrentHashMap,用作存储过滤器的,并有一些基本的CURD过滤器的方法,代码如下:

6ff83fa40e4b9cd68cf429db0588a024.png

FilterLoader类持有FilterRegistry,FilterFileManager类持有FilterLoader,所以最终是由FilterFileManager注入 filterFilterRegistry的ConcurrentHashMap的。FilterFileManager到开启了轮询机制,定时的去加载过滤器,代码如下:

4434d257a4c6465e9a5cfba254bbd2f9.png

Zuulservlet作为类似于Spring MVC中的DispatchServlet,起到了前端控制器的作用,所有的请求都由它接管。它的核心代码如下:

f7151441ba360298e47fe149df64c636.png

跟踪init(),可以发现这个方法为每个请求生成了RequestContext,RequestContext继承了ConcurrentHashMap,在请求结束时销毁掉该RequestContext,RequestContext的生命周期为请求到zuulServlet开始处理,直到请求结束返回结果。 RequestContext类在存储了很多重要的信息,包括HttpServletRequest、HttpServletRespons、ResponseDataStream、ResponseStatusCode等。 RequestContext对象在处理请求的过程中,一直存在,所以这个对象为所有Filter共享。

从ZuulServlet的service()方法可知,它是先处理pre()类型的处理器,然后在处理route()类型的处理器,最后再处理post类型的处理器。

首先来看一看pre()的处理过程,它会进入到ZuulRunner,该类的作用是将请求的HttpServletRequest、HttpServletRespons放在RequestContext类中,并包装了一个FilterProcessor,代码如下:

fb1c3c0cbe0216ebcc403b217937cfec.png

而FilterProcessor类为调用filters的类,比如调用pre类型所有的过滤器:

29d2ab19e6e6c460667347a16ba5ec32.png

跟踪runFilters()方法,可以发现,它最终调用了FilterLoader的getFiltersByType(sType)方法来获取同一类的过滤器,然后用for循环遍历所有的ZuulFilter,执行了 processZuulFilter()方法,跟踪该方法可以发现最终是执行了ZuulFilter的方法,最终返回了该方法返回的Object对象。

875342b961c3985dd79464b8ef224e43.png

route、post类型的过滤器的执行过程和pre执行过程类似。

Zuul默认过滤器

默认的核心过滤器一览表

Zuul默认注入的过滤器,它们的执行顺序在FilterConstants类,我们可以先定位在这个类,然后再看这个类的过滤器的执行顺序以及相关的注释,可以很轻松定位到相关的过滤器,也可以直接打开 spring-cloud-netflix-core.jar的 zuul.filters包,可以看到一些列的filter,现在我以表格的形式,列出默认注入的filter.

eca8265958fdc57a34c0d205ec86bee6.png
e7597b51f732b5da5fe3535396bc1497.png

过滤器的order值越小,就越先执行,并且在执行过滤器的过程中,它们共享了一个RequestContext对象,该对象的生命周期贯穿于请求,可以看出优先执行了pre类型的过滤器,并将执行后的结果放在RequestContext中,供后续的filter使用,比如在执行PreDecorationFilter的时候,决定使用哪一个route,它的结果的是放在RequestContext对象中,后续会执行所有的route的过滤器,如果不满足条件就不执行该过

滤器的run方法。最终达到了就执行一个route过滤器的run()方法。

而error类型的过滤器,是在程序发生异常的时候执行的。

post类型的过滤,在默认的情况下,只注入了SendResponseFilter,该类型的过滤器是将最终的请求结果以流的形式输出给客户单。

现在来看SimpleHostRoutingFilter是如何工作?

进入到SimpleHostRoutingFilter类的方法的run()方法,核心代码如下:

043133ce4afe98f03cb8f863d6726615.png

查阅这个类的全部代码可知,该类创建了一个HttpClient作为请求类,并重构了url,请求到了具体的服务,得到的一个CloseableHttpResponse对象,并将CloseableHttpResponse对象的保存到RequestContext对象中。并调用了ProxyRequestHelper的setResponse方法,将请求状态码,流等信息保存在RequestContext对象中。

9e63b790c374c4ebba45e270eb837837.png

现在来看SendResponseFilter是如何工作?

这个过滤器的order为1000,在默认且正常的情况下,是最后一个执行的过滤器,该过滤器是最终将得到的数据返回给客户端的请求。

在它的run()方法里,有两个方法:addResponseHeaders()和writeResponse(),即添加响应头和写入响应数据流。

2c55549c909f4ac10a1d68a19f325d14.png

其中writeResponse()方法是通过从RequestContext中获取ResponseBody获或者ResponseDataStream来写入到HttpServletResponse中的,但是在默认的情况下ResponseBody为null,而ResponseDataStream在route类型过滤器中已经设置进去了。具体代码如下:

160760fe2ae9fd0db6088cd4d62d4f22.png

如何在zuul上做日志处理

由于zuul作为api网关,所有的请求都经过这里,所以在网关上,可以做请求相关的日志处理。 我的需求是这样的,需要记录请求的 url,ip地址,参数,请求发生的时间,整个请求的耗时,请求的响应状态,甚至请求响应的结果等。 很显然,需要实现这样的一个功能,需要写一个ZuulFliter,它应该是在请求发送给客户端之前做处理,并且在route过滤器路由之后,在默认的情况下,这个过滤器的order应该为500-1000之间。那么如何获取这些我需要的日志信息呢?找RequestContext,在请求的生命周期里这个对象里,存储了整个请求的所有信息。

现在编码,在代码的注释中,做了详细的说明,代码如下:

9784224ca783787104dee410fc929750.png

现在读者也许有疑问,如何得到的statrtTime,即请求开始的时间,其实这需要另外一个过滤器,在网络请求route之前(大部分耗时都在route这一步),在过滤器中,在RequestContext存储一个时间即可,另写一个过滤器,代码如下:

b1cde7bda8e6f1315be875d9d59b7c1f.png

可能还有这样的需求,我需要将响应结果,也要存储在log中,在之前已经分析了,在route结束后,将从具体服务获取的响应流存储在RequestContext中,在SendResponseFilter过滤器写入在HttpServletResponse中,最终返回给客户端。那么我只需要在SendResponseFilter写入响应流之前把响应流写入到 log日志中即可,那么会引发另外一个问题,因为响应流写入到 log后,RequestContext就没有响应流了,在SendResponseFilter就没有流输入到HttpServletResponse中,导致客户端没有任何的返回数据,那么解决的办法是这样的:

InputStream inputStream =RequestContext.getCurrentContext().getResponseDataStream();InputStream newInputStream= copy(inputStream);transerferTolog(inputStream);RequestContext.getCurrentContext().setResponseDataStream(newInputStream);

从RequestContext获取到流之后,首先将流 copy一份,将流转化下字符串,存在日志中,再set到RequestContext中, 这样SendResponseFilter就可以将响应返回给客户端。这样的做法有点影响性能,如果不是字符流,可能需要做更多的处理工作。

原文地址:https://dwz.cn/9tKgRhJF
作者:方志朋

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/503905.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一加到1亿。C语言_可能是今年最难选的2部手机:小米10详细对比一加8T

原标题:可能是今年最难选的2部手机:小米10详细对比一加8T在智能手机行业里流传着这样一句话:旗舰处理器只能决定一款机型的下限,而不能决定它的上限;决定一款机型上限的是旗舰处理器之外的屏幕、拍照、UI等等。这句话放…

html5 webrtc fir 请求关键帧_中信建投官网强调认可我们的投资理念的股民朋友请求 CTRL D 收藏、锁定本直播地址...

本文摘要:有关中信建投官网强调认可我们的投资理念的股民朋友请求 CTRL D 收藏、锁定本直播地址的内容分享,跟踪了解如何看股票k线图,分享热点专题。欢迎来到 橘子股票直播间,本直播每日为大家更新最快、最精准、最全面的股市内容…

打印完全二叉树java_java 完全二叉树的构建与四种遍历方法示例

本来就是基础知识,不能丢的太干净,今天竟然花了那么长的时间才写出来,记一下。有如下的一颗完全二叉树:先序遍历结果应该为:1 2 4 5 3 6 7中序遍历结果应该为:4 2 5 1 6 3 7后序遍历结果应该为…

模拟 http connecttimeout_燃烧室数学模型模拟软件NPSS

燃烧室的各个结构都可以被建立数学模型用矩阵进行模拟计算,每个模型都由输入、定义各部件的参数以及输出组成。流体在系统中某个点的状态可以由速率、压力、温度和构成(例如铝粉和氢气的质量比例)等参数描述。由于各个参数之间存在反馈环路,导致输入和输…

两个时间点距离 time_t c_天津二建公路考试时间

天津二建公路考试时间 Vadg42d天津二建公路考试时间 预警体系通过预警分析和预控对策实现事故的预警和控制,预警分析完成监测、识别、诊断与评价功能,而预控对策完成对事故征兆的不良趋势进行纠错和治错的功能。技术方案现金流量表主要有投资现金流量表&…

java 168转换成861_java实验-java语言面向对象编程基础

java实验-java语言面向对象编程基础 (12页)本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦!8.90 积分广州大学学生实验报告广州大学学生实验报告开课学院及实验室:开课学院及实验室&#xf…

c#养老院老人信息管理系统源码 论文_辽宁吃的好的社区养老院位置,爱心养老院_抚顺市望花区社会养老中心...

首页 > 新闻中心发布时间:2020-11-09 02:11:16 导读:抚顺市望花区社会养老中心为您提供辽宁吃的好的社区养老院位置,爱心养老院的相关知识与详情: 老人早晨气场后手指经常发硬,无法自己握拳。 老人关节活动不方便,活…

SQL进阶:子查询

一般情况下,我们都是直接对表进行查询,但有时候,想要的数据可能通过一次select 获取不到,需要嵌套select,这样就形成了子查询。 子查询可以位于查询语句的任意位置,主要的注意点在于用于不同的位置,和不同的关键字一起使用时,需要注意返回的列的数量和行的数量。 位于…

android四周阴影效果_帮助独立开发者轻松创建令人惊叹的产品视觉效果

大家好,我是独立开发者Larry~作品发布、宣传交流过程中对作品进行样机包装或场景展示往往是不可或缺的,除了纯手工打造外,通常大家都会运用一些样机素材来完成对产品的快速包装,因此关于样机素材的资源网上有很多&…

pythonweb全栈开发_Web全栈开发穿插路程(python+js)

简介:穿插路程,是指快去快回,来去一阵风,走的快,走马观花,没有细品。细品那就要慢慢熬功夫喽。1.完成后的效果是:用户访问入口页面,录入信息,提交后结果以逐步添加的形式…

C++和Rust_Kotlin、Rust两个充满了骚操作的编程语言,值得一玩

Kotlin和Rust都是两个年轻的编程语言,而且相比现在流行的Python、JavaScript/Typescript语言来说,Kotlin和Rust更接近底层,对于学习理解计算机原理,学习Kotlin和Rust应该是更好的选择。与C/C相比,Kotlin、Rust做上层应…

理发店管理系统java_美容美发店管理系统的设计与实现(JSP,SQLServer)(含录像)

美容美发店管理系统的设计与实现(,SQLServer)(含录像)(开题报告,论文12700字,程序代码,SQLServer数据库)系统功能结构本系统是根据我国美容业的现状及中小型美容院的发展需要进行详细的分析, 对美容院信息管理系统进行合理的设计, 实现集成员工管理、工资…

cpu频率_新版win10修复CPU频率显示不正确的bug

在此前win10 2020年5月更新后,有用户反馈win10任务管理器无法正确显示CPU使用率和频率,比如会出现CPU频率为0.00GHz。现在有外媒报道,微软在win10测试版19042.608中修复了CPU频率显示不正确的bug。这一消息也得到了微软的确认表示已经修复了某…

sap fiori导出列表到excel_介绍一种Fiori标准应用的增强方式

2015年,Jerry还在SAP成都研究院CRM Fiori开发团队工作时,担任了德国一个著名的灯具制造商客户的CRM Fiori项目的dev angel. 当时客户提出了若干对CRM Fiori标准应用的增强需求,总的来说分为前台Fiori UI界面的增强(比如增添新的自定义字段)以…

电脑ip地址设置_路由器动态IP和静态IP上网方式怎么设置【设置教程】

在我们设置路由器的过程中,路由器设置界面一般会给我们提供4种上网方式选项,分别是:“让路由器自动选择上网方式(推荐)”、“PPPoE(ADSL虚拟拨号)”、“动态IP(以太网宽带,自动从服务商获取IP地址)”、“静态IP(以太网宽带&#x…

钉钉关键字回复功能_在家办公首日:钉钉、企业微信集体“崩溃”,只能选择 QQ、微信...

今日是春节假期结束后的第一个工作日,不少企业规定2月3-7日可以在家远程办公。不过尴尬的是,今日上午,钉钉、企业微信等在线办公App集体出现问题。不少网友反馈钉钉出现Bug,“不知道大家工作的怎么样,我的钉钉刚才一直…

python决策树 value_机器学习 | 算法笔记(四)- 决策树算法以及代码实现

概述上一篇讲述了《机器学习 | 算法笔记(三)- 支持向量机算法以及代码实现》,本篇讲述机器学习算法决策树,内容包括模型介绍及代码实现。决策树决策树(Decision Tree)在机器学习中也是比较常见的一种算法,属于监督学习中的一种。看字面意思应…

监听手指是否离开屏幕android_Flutter事件监听

一. 事件监听 在大前端的开发中,必然存在各种各样和用户交互的情况:比如手指点击、手指滑动、双击、长按等等。所有内容首发于公众号:coderwhy在Flutter中,手势有两个不同的层次:第一层:原始指针事件&#…

@excel注解_Excel导入导出Java解决方案推荐

今天锋哥介绍一款Excel导入导出Java解决方案Easy-POI,以前我们用POI,麻烦点,Easy-POI是封装好的,用起来Easy点,封装过,性能好,所以大伙有空可以研究下;Easy-POIEasy-POI是一款Excel导…

wind 下装mysql,windows 下安装MySQL

下载压缩包首先到官网下载安装包,可联系提供配置环境变量找到系统属性(windows10在高级系统设置)在这里插入图片描述找到系统变量的 Path 点击编辑在这里插入图片描述点击新建,然后添加进去自己压缩包位置的bin目录在这里插入图片描述之后点击三个确当 (同时自动关闭…