SpringCloud解析之Zuul(一)
本文基于Spring Cloud Edgware.SR6,Zuul版本1.3.1,解析Zuul的请求拦截机制,让大家对Zuul的原理有个大概的认识和了解。如有不对的地方,欢迎指正。
spring boot启动过程中,一系列spring管理的bean会被初始化,其中包括ZuulController,它通过继承ServletWrappingController来初始化ZuulServlet



spring boot启动完成后,通过浏览器发起网关请求,请求会到达DispatcherServlet.doDispatch(),此方法会查找符合的Handler和HandlerAdapter来处理请求。我们来看下它是如何找到zuul的handler。

this.handlerMappings中包含了当前应用所有继承HandlerMapping接口的实现类,通过遍历它来查找符合当前request请求的HandlerExecutionChain

进来发现调用的是AbstractHandlerMapping.getHandler(),内部先调用AbstractUrlHandlerMapping.getHandlerInternal(),查询匹配的handler,如果没有,则使用默认的handler,然后包装成HandlerExecutionChain返回。


AbstractUrlHandlerMapping.getHandlerInternal()方法内部调用了lookupHandler()。


进来发现是ZuulHandlerMapping重写的lookupHandler()。该方法首先判断是否有异常,没有的话再判断是否是忽略的请求,不是的话就注册handlers,然后调用父类的
lookupHandler()方法返回。


我们看下registerHandlers()做了什么。this.routeLocator.getRoutes()就是获取注册在eureka的服务列表,然后遍历,
依次保存到AbstractUrlHandlerMapping.handlerMap中

再来看下super.lookupHandler(urlPath, request)。
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
// 这里就从上面注册好的handlerMap中获取请求urlPath对应的handler
Object handler = this.handlerMap.get(urlPath);
if (handler != null) {
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
return buildPathExposingHandler(handler, urlPath, urlPath, null);
} // 如果获取不到,则进行正则匹配,如果还匹配不到的话,则返回null
List<String> matchingPatterns = new ArrayList<String>();
for (String registeredPattern : this.handlerMap.keySet()) {
if (getPathMatcher().match(registeredPattern, urlPath)) {
matchingPatterns.add(registeredPattern);
}
else if (useTrailingSlashMatch()) {
if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
matchingPatterns.add(registeredPattern +"/");
}
}
} String bestMatch = null;// 匹配到之后,用请求urlPath对应的patternComparator,对所有匹配的url进行排序,之后获取第一个匹配的url
Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
if (!matchingPatterns.isEmpty()) {
Collections.sort(matchingPatterns, patternComparator);
if (logger.isDebugEnabled()) {
logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
}
bestMatch = matchingPatterns.get(0);
}
if (bestMatch != null) {// 先根据排序后的第一个url获取对应的handler,如果没有的话则用”/”再取一次handler = this.handlerMap.get(bestMatch);
if (handler == null) {
if (bestMatch.endsWith("/")) {
handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1));
}
if (handler == null) {
throw new IllegalStateException(
"Could not find handler for best pattern match [" + bestMatch + "]");
}
}
// 如果handler是String,则从应用上下文中获取对应的bean
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);// 解析映射url的后半段请求uriString pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath); // 最后再确认一次bestMatch是否是最匹配请求的路由
Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();
for (String matchingPattern : matchingPatterns) {
if (patternComparator.compare(bestMatch, matchingPattern) == 0) {
Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
uriTemplateVariables.putAll(decodedVars);
}
}
if (logger.isDebugEnabled()) {
logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);
}// 构建HandlerExecutionChain并返回return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables);
} // No handler found...
return null;
}
至此,终于找到了zuul的handler,其中有些细节没有提或是略过,有兴趣的朋友可以自行下去翻阅。
总结一下:
1.请求执行到DispatcherServlet.doDispatch(),此方法中调用getHandler(),遍历所有实现handlerMapping接口的实现类来查找请求对应的HandlerExecutionChain
2.getHandler()内部是遍历执行AbstractHandlerMapping.getHandler(),它的内部又是执行的AbstractUrlHandlerMapping.getHandlerInternal(),而AbstractUrlHandlerMapping内部调用的lookupHandler()实则是ZuulHandlerMapping重写的lookupHandler(),目的是获取注册中心的消费者路由列表,
3.然后ZuulHandlerMapping调用父类AbstractUrlHandlerMapping的lookupHandler(),用请求url匹配路由列表,获取最匹配的一个路由,包装成HandlerExecutionChain返回
SpringCloud解析之Zuul(一)的更多相关文章
- SpringCloud解析之Zuul(二)
本文基于Spring Cloud Edgware.SR6,Zuul版本1.3.1,解析Zuul的请求拦截机制,让大家对Zuul的原理有个大概的认识和了解.如有不对的地方,欢迎指正. 在上一期的Spri ...
- SpringCloud学习之zuul
一.为什么要有网关 我们先看一个图,如果按照consumer and server(最初的调用方式),如下所示 这样我们要面临如下问题: 1. 用户面临着一对N的问题既用户必须知道每个服务.随着服务的 ...
- springcloud 实战 网关zuul使用中遇到的相关问题
springcloud 实战 网关zuul使用中遇到的相关问题 1.网关zuul使用时,跨域问题在网关中配置pre过滤器: response.setHeader("Access-Contr ...
- 基于SpringCloud搭建项目-Zuul篇(六)
本文主要介绍zuul的基本原理和在sprngcloud服务下如何使用 一.简单介绍 Zuul 是 Netflix OSS 中的一员,是一个基于 JVM 路由和服务端的负载均衡器.提供路由.监控.弹性. ...
- SpringCloud学习之Zuul统一异常处理及回退
一.Filter中统一异常处理 其实在SpringCloud的Edgware SR2版本中对于ZuulFilter中的错误有统一的处理,但是在实际开发当中对于错误的响应方式,我想每个团队都有自己的处理 ...
- SpringCloud之网关 Zuul(四)
一 Zuul简介 zuul 是netflix开源的一个API Gateway 服务器, 本质上是一个web servlet应用. Zuul 在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架.Z ...
- SpringCloud 进阶之Zuul(路由网关)
1. Zuul(路由网关) Zuul 包含了对请求的路由和过滤两个最主要的功能; 路由功能:负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础; 过滤功能:负责对请求的处理过程进行干 ...
- springcloud微服务总结 zuul
一 springcloud网关组件理解: 为什么需要网关呢? 我们知道我们要进入一个服务本身,很明显我们没有特别好的办法,直接输入IP地址+端口号,我们知道这样的做法很糟糕的,这样的做法大有问题,首先 ...
- SpringCloud路由网关Zuul
一.什么是网关 Zuul的主要功能是路由转发和过滤器.路由功能是微服务的一部分,比如/api/user转发到到user服务,/api/shop转发到到shop服务.zuul默认和Ribbon结合实现了 ...
随机推荐
- Android零基础入门第7节:搞定Android模拟器,开启甜蜜之旅
原文:Android零基础入门第7节:搞定Android模拟器,开启甜蜜之旅 在前几期中总结分享了Android的前世今生.Android 系统架构和应用组件那些事.带你一起来聊一聊Android开发 ...
- UWP项目生成安装包远程安装在树莓派上
原文: UWP项目生成安装包远程安装在树莓派上 哎,好纠结啊!如果这个名字写的太长,会显得太繁琐,如果写的短又好像说不清楚,我这语言表达水平实在是令人担忧啊!不过应该能够明白啥意思吧!因为对这个感兴趣 ...
- 改善C#程序的建议8:避免锁定不恰当的同步对象
原文:改善C#程序的建议8:避免锁定不恰当的同步对象 在C#中让线程同步的另一种编码方式就是使用线程锁.所谓线程锁,就是锁住一个资源,使得应用程序只能在此刻有一个线程访问该资源.可以用下面这句不是那么 ...
- mac下实现代码远程同步
近期将办公电脑从windows换成了mac,以前一直用windows,在windows下面将代码同步到远程的开发机,zend studio有一些内置的工具,但mac下的zend stduio没有了这个 ...
- 国外优秀的UI设计资源库收集
国外优秀的UI设计资源库 网站设计或者说UI设计对于Web上的运用是非常的关键,一个站做得好不好,能不能吸引人的眼球,设计占了不低的地位,但话又说回来,Web前端人员又有多少人是设计专业毕业,具有这方 ...
- How Qt Signals and Slots Work(感觉是通过Meta根据名字来调用)
Qt is well known for its signals and slots mechanism. But how does it work? In this blog post, we wi ...
- mysql远程表链接
FEDERATED简介 FEDERATED存储引擎是访问远程数据库中的表,在平时开发中可以用此特性来访问远程库中的参数表之类的,还是非常方便的.使用时直接在本地构建一个federated表来链接远程数 ...
- 反汇编分析__stdcall和__cdecl的异同
C++代码如下:.h头文件 #pragma once#ifdef DLLTestAPI#else#define DLLTestAPI _declspec(dllimport)#endifint DLL ...
- Qt之Model-View架构(雨田哥的博客)
Qt之Model-View架构 Qt之Model-View架构 简述 效果图 代码 结尾 简述 为什么会用这个模式,这里我就不解释了,可以看下 豆子哥的见解 .这里我只是如何去使用的.供大家共同探讨学 ...
- c++ LeetCode (初级字符串篇) 九道算法例题代码详解(二)
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11089327.html 已经刷了很多篇leetcode题了,不过最近在找c++的实习工作(大佬 ...