Zuul源码分析
先上一张流程图:

我们Zuul的使用如下:
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class);
}
}
application.properties配置:
zuul.routes.study-trade.service-id=study-trade
zuul.routes.study-trade.path=/orderservice/**
从我们的开启Zuul注解@EnableZuulProxy开始看起,这个比较简单,就是引入了ZuulProxyMarkerConfiguration.Marker这个Bean。
再找到Zuul这个包下面的spring.factories这个文件,里面有两个类,我们看一下

有一个是ZuulServerAutoConfiguration类,它里面初始化了ZuulHandlerMapping,ZuulController,ZuulServlet。还有一个zuulProperties变量,它会将我们application.yml文件里配置的路由映射规则读进来
而另一个类ZuulProxyAutoConfiguration,他重要的一点是会初始化RibbonRoutingFilter,PreDecorationFilter,SimpleHostRoutingFilter
以上就是应用初始化相关的准备
当我们请求过来时会怎么样呢?
我使用orderservice前缀来访问study-trade服务:http://localhost:8000/orderservice/trade/testTrade/3
7. 请求发送过来走到ZuulHandlerMapping,并调用到registerHandlers方法,routes就是我application.yml里配置的映射关系
private void registerHandlers() {
Collection<Route> routes = this.routeLocator.getRoutes();
if (routes.isEmpty()) {
this.logger.warn("No routes found from RouteLocator");
}
else {
for (Route route : routes) {
//注册到
registerHandler(route.getFullPath(), this.zuul);
}
}
}
- 在走到DispatcherServlet里的doDispatch方法,然后使用ZuulController取处理请求
//mappedHandler.getHandler()就是ZuulController
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
- ZuulController接收到请求,会使用ZuulServlet来处理请求,他的service方法如下:
public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {
try {
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();
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();
}
}
可以看出他里面调用了preRoute,postRoute,route。我们自己定义的Filter也是通过这里的代码得以执行的。
10. 点开ZuulServlet的preRoute等这几个方法时,看到他其实又是使用ZuulRunner来处理的
void preRoute() throws ZuulException {
zuulRunner.preRoute();
}
void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {
zuulRunner.init(servletRequest, servletResponse);
}
- 以preRoute()方法为例,它里面又是使用了FilterProcessor.getInstance()来处理方法,看 FilterProcessor.getInstance()样子,感觉是一个单例,点进去看了下,确实是使用了饿汉模式的单例。
public void preRoute() throws ZuulException {
FilterProcessor.getInstance().preRoute();
}
- 接下来一起探究下FilterProcessor类吧
public void preRoute() throws ZuulException {
try {
runFilters("pre");
} catch (ZuulException e) {
throw e;
} catch (Throwable e) {
throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_PRE_FILTER_" + e.getClass().getName());
}
}
public Object runFilters(String sType) throws Throwable {
if (RequestContext.getCurrentContext().debugRouting()) {
Debug.addRoutingDebug("Invoking {" + sType + "} type filters");
}
boolean bResult = false;
//找到相应sType的ZuulFilter集合,然后执行run方法
List<ZuulFilter> list = FilterLoader.getInstance().getFiltersByType(sType);
if (list != null) {
for (int i = 0; i < list.size(); i++) {
ZuulFilter zuulFilter = list.get(i);
Object result = processZuulFilter(zuulFilter);
if (result != null && result instanceof Boolean) {
bResult |= ((Boolean) result);
}
}
}
return bResult;
}
相当于是FilterProcessor从filterloader中获取zuulfilter。而zuulfilter是被filterFileManager所加载,并支持groovy热加载,采用了轮询的方式热加载。有了这些filter之后,zuulservelet首先执行的Pre类型的过滤器,再执行route类型的过滤器,最后执行的是post类型的过滤器,如果在执行这些过滤器有错误的时候则会执行error类型的过滤器。执行完这些过滤器,最终将请求的结果返回给客户端。 RequestContext就是会一直跟着整个请求周期的上下文对象,filters之间有什么信息需要传递就set一些值进去就行了。
- 那么是怎么调用其他服务的呢?其中有一个RibbonRoutingFilter,就实现了调用其他服务的方法,具体内容不表
- 附上一张更全的架构设计图

Zuul源码分析的更多相关文章
- zuul源码分析-探究原生zuul的工作原理
前提 最近在项目中使用了SpringCloud,基于zuul搭建了一个提供加解密.鉴权等功能的网关服务.鉴于之前没怎么使用过Zuul,于是顺便仔细阅读了它的源码.实际上,zuul原来提供的功能是很单一 ...
- Spring Cloud Zuul源码
一.Zuul源码分析(初始化流程.请求处理流程)
- SpringCloud微服务如何优雅停机及源码分析
目录 方式一:kill -9 java进程id[不建议] 方式二:kill -15 java进程id 或 直接使用/shutdown 端点[不建议] kill 与/shutdown 的含义 Sprin ...
- ApplicationEvent事件机制源码分析
<spring扩展点之三:Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法,在spring启动后做些事情> <服务网关zu ...
- 源码分析:Semaphore之信号量
简介 Semaphore 又名计数信号量,从概念上来讲,信号量初始并维护一定数量的许可证,使用之前先要先获得一个许可,用完之后再释放一个许可.信号量通常用于限制线程的数量来控制访问某些资源,从而达到单 ...
- ABP源码分析一:整体项目结构及目录
ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...
- HashMap与TreeMap源码分析
1. 引言 在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...
- nginx源码分析之网络初始化
nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...
- zookeeper源码分析之五服务端(集群leader)处理请求流程
leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...
随机推荐
- JS 的基础概念
本篇文章主要讲述js的基础知识! 首先,我们要明白什么是JS,JS就是 javascript 的简称,是一种轻量级,弱类型的脚本语言,已经被广泛用于Web应用开发,常用来为网页添加各式各样的动态功能, ...
- 快速搭建网站信息库(小型Zoomeye)
前言:本来是不想重复造车轮的,网上资料有开源的fofa,和一些设计.有的架设太复杂了,好用东西不会用,整个毛线.还有的没有完整代码. 设计方案: 测试平台:windows 测试环境:php ...
- CSS选择器与CSS的继承,层叠和特殊性
什么是选择器?选择器{样式;},在{}之前的部分就是"选择器","选择器"指明了{}中的"样式"的作用对象,也就是"样式" ...
- python正则表达式详解之Match类及其方法
1.Match对象简介 match对象通常是由正则表达式对象的match 方法,search 方法等经过匹配之后而产生.可以直接当做bool值使用,如果匹配则相当于True, 如果不匹配,则返回Non ...
- [Abp vNext 入坑分享] - 4.JWT授权的接入
一.感想 在写这一系列文章之前,本来以为写这个之前已经搭建好的框架描述会比较简单,但是慢慢写下来才发现.写这个真的不简单额,本来以为图文一起,一个晚上应该能输出一篇吧...结果:现实真的骨感,一个星期 ...
- 【<meta name="" content=">】的作用
一.语法: <meta name="name" content="string"/> 二.参数解析: 1.name项:常用的选项有keywords( ...
- hash算法解决冲突的方案
1, 开放定址法: 所谓的开放定址法就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入 公式为:fi(key) = (f(key)+di) MOD m ...
- Libra教程之:Transaction的生命周期
文章目录 Transaction的生命周期 提交一个Transaction 交易入链的详细过程 接收Transaction 和其他Validators共享这个Transaction 区块Proposi ...
- 【Linux常见命令】ls命令
ls - list directory contents ls命令用于显示指定工作目录下之内容(列出目前工作目录所含之文件及子目录). 语法: ls [OPTION]... [FILE]... l ...
- 狄慧201771010104《面向对象程序设计(java)》第十六周学习总结
实验十六 线程技术 实验时间 2017-12-8 一.知识点总结: 1.程序与进程的概念 ‐程序是一段静态的代码,它是应用程序执行的蓝本. ‐进程是程序的一次动态执行,它对应了从代码加载.执行至执行 ...