今天我们分析下 SpringCloud 是怎么整合 Zuul 的。
回顾
-
Zuul是通过ZuulServletFilter
或者 ZuulServlet
接管我们的请求
-
Zuul整个流程如下:
ZuulServletFilter(ZuulServlet)
-> ZuulRunner
-> FilterProcessor
-> ZuulFilter
目标
明确SpringMVC和Zuul框架是怎么配合的
引入Zuul的版本信息
Zuul功能启用及配置的加载
Zuul的启用 - @EnableZuulProxy
ZuulProxyAutoConfiguration - Zuul自动配置Bean
ZuulServerAutoConfiguration - Zuul自动配置Bean
以上两个类,加载了Zuul的相关配置类:
-
拦截请求:
- 和SpringMVC结合的Bean:
ZuulController
、ZuulHandlerMapping
- 通过Web Filter拦截请求Bean:
ZuulServletFilter
-
Zuul流程需要的Bean:
默认的ZuulFilters
Pre Filter
-
ServletDetectionFilter
order = -3
作用:判断请求是否是由DispatcherServlet
or ZuulServlet
传来的,并把判断结果以键值对的形式放在RequestContext
-
Servlet30WrapperFilter
order = -2
作用:包装request,兼容servlet3.0
-
FormBodyWrapperFilter
order = -1
作用:包装表单数据并为下游服务重新编码
-
DebugFilter
order = 1
作用:如果debug请求,那么会在RequestContext
中标记为debug请求和routing
-
PreDecorationFilter
= 5
作用:请求路由和zuul路由配置进行匹配,并设置与代理相关的头部信息
Route Filter
-
RibbonRoutingFilter
order = 10
作用:使用Ribbon、Hytrix和可插拔的httpClient发送请求,serviceId、是否重试以及负载均衡策略在相关联的RequestContext
获取
-
SimpleHostRoutingFilter
order = 100
作用:用HttpClient发送请求到预定的URLs,URLs通过RequestContext#getRouteHost()
获取
-
SendForwardFilter
order = 500
作用:用RequestDispatcher
forwards请求,转发的地址是RequestContext
的FilterConstants#FORWARD_TO_KEY
对应value
Post Filter
-
SendResponseFilter
order = 1000
作用:写 代理的请求得到的响应 到 当前响应
Error Filter
-
SendErrorFilter
order = 0
作用:如果RequestContext#getThrowable()
不为空,默认将请求转发到 /error
SpringMVC怎么把请求转发给Zuul?
从配置类分析
从上述配置可以看下几个重要的配置类源码:
ZuulController
ServletWrappingController
ZuulHandlerMapping
以上配置类:
ZuulController
:它是ServletWrappingController
的 子类,将请求给到ZuulServlet
去处理
ZuulHandlerMapping
:它是AbstractUrlHandlerMapping
的子类,将请求路由到ZuulController
处理
ZuulServlet
:由上一篇知道它是Zuul流程的入口之一
回顾SpingMVC对于请求的处理流程
- 客户端请求交给SpringMVC的
DispatcherServlet
统一处理
- 通过已经注册的
HandlerMapping
, 根据请求路由找到处理器执行链HandlerExecutionChain
,包括请求各个拦截器HandlerInterceptor
和请求处理器handler
- 找到请求处理器对应的适配器
HandlerAdapter
- 执行已注册的各拦截器的
preHandle
方法
- 调用处理器处理请求,返回模型数据以及视图
ModelAndView
- 执行已注册的各拦截器的
postHandle
方法
- 根据给定的
ModelAndView
进行渲染
- 响应客户端
结合SpingMVC对于请求的处理流程可以猜到,当请求给到SpringMVC的DispatcherServlet
后,如果该路由是需要Zuul拦截的请求,那么会匹配到ZuulHandlerMapping
,从而找到处理器ZuulController
,之后在处理的时候,会交给ZuulServlet
,后面的流程见上一篇文章。
Debug验证
zuul拦截配置:
请求:curl -v http://127.0.0.1:8080/test
图示过程:
结果显示:猜想是正确的。
大致流程:DispatcherServlet
-> ZuulController
-> ZuulServlet
-> 执行各阶段ZuulFilters
ZuulServletFilter - 另一种拦截请求流程
配置
ZuulServletFilter
的URL匹配规则是/zuul
, 而且如果要是使得ZuulServletFilter
Bean加载,必须在配置文件中,添加:zuul.use-filter=true
,如图:
ZuulServletFilter源码
源码很简单,在请求上下文添加了一个标志位zuulEngineRan
为true。并执行父类com.netflix.zuul.filters.ZuulServletFilter
的doFilter
方法,进而进入了Zuul的核心流程当中,后面的流程我们已经熟悉了。
其中要注意下,com.netflix.zuul.filters.ZuulServletFilter
虽然是Filter,但是并没有在其doFilter
方法中调用FilterChain
的doFilter
方法,我们可以回想下,如果是我们自己写FIlter,一定会调用。之所以ZuulServletFilte
没有这么做,是因为它要接管请求,并不要Servlet来处理。
大致流程如图:
总结
Zuul和Spring结合并接管请求主要有两种方式:
- 在Spring容器中通过注册请求处理器
ZuulController
和路由处理器的映射ZuulHandlerMapping
,做到请求的拦截,并内置了一些ZuulFIlter保证请求的处理。
- 通过注册
ZuulServletFilter
,使用Filter方式接管请求,注意默认的路径匹配及生效配置