参考资料:
Spring Cloud 官网
Zuul wiki
相关版本:zuul 1.3.1,spring boot 2.1.4 ,spring cloud Greenwich.SR1
回顾
在 Spring Cloud Zuul【源码篇】揭秘 Zuul 中知道了 Zuul 本质是由 Servlet 和 Filter 组成。
其中 Servlet 用来接收请求,而 ZuulFilter 则对请求进行包装以及处理,如:请求转发,客户端负载均衡,熔断等。
Zuul 过滤链执行顺序
Zuul 提供了一些 ZuulFilter ,有的用来做请求封装,有的用来处理请求。
这些 ZuulFilter 各自有各自的作用,并且存在执行顺序。为了规范 ZuulFilter 的执行,Zuul 针对 ZuulFilter 的执行顺序进行了如下定义
-
根据 pre、route、 post route 进行区分。
pre 优先级最高。
route 优先级次之。
post route 优先级最低。 -
根据上面的区分之后,每个类别中又有给的优先级。
验证 ZuulFilter 执行顺序
根据 pre、route、 post route 进行区分
查看源码 ZuulServlet#service 能够知道 ZuulFilter 根据类型 pre -> route -> post 优先级由高到低以此执行过滤操作。
public class ZuulServlet extends HttpServlet {
public void service(......){
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;
}
}
}
Netflix 官方文档中,给定了一张图片同样说明了根据类型的执行顺序
根据 order执行顺序
根据类型(pre、route、post) 分类执行之后,每一个分类有各自的执行顺序排列,排列参数: filterOrder 。数字越小,优先级越高。
Zuul 1.3.1 版本中 默认提供的 ZuulFilter
pre filters
过滤类 | 优先级(越小越优先) |
---|---|
ServletDetectionFilter | -3 |
Servlet30WrapperFilter | -2 |
FormBodyWrapperFilter | -1 |
DebugFilter | 1 |
PreDecorationFilter | 5 |
route filters
过滤类 | 优先级(越小越优先) |
---|---|
RibbonRoutingFilter | 10 |
SimpleHostRoutingFilter | 100 |
SendForwardFilter | 500 |
post filters
过滤类 | 优先级(越小越优先) |
---|---|
SendErrorFilter | 0 |
SendResponseFilter | 1000 |
Zuul 1.3.1 版本提供的 ZuulFilter 功能简介
- 在 Zuul 中所有的 Filter 都需要继承 ZuulFilter。
- 默认 ZuulFilter 是否启用有两个判断条件 1、zuul.{FilterCLass}.{FilterType}.disable :false 开启,true 关闭 2、ZuulFilter#shouldFilter 方法,返回 true 执行,返回 false 不执行
- ZuulFilter 判定成功之后执行 ZuulFilter#run() 方法
pre filter
ServletDetectionFilter
ZuulFilter 执行触发条件
public class ServletDetectionFilter extends ZuulFilter {
// 拦截所有请求
public boolean shouldFilter() {
return true; }
}
只要该过滤器开启,拦截所有请求进行过滤处理。
过滤执行逻辑
public class ServletDetectionFilter extends ZuulFilter {
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
if (!(request instanceof HttpServletRequestWrapper)
&& isDispatcherServletRequest(request)) {
ctx.set(IS_DISPATCHER_SERVLET_REQUEST_KEY, true);
}
else {
ctx.set(IS_DISPATCHER_SERVLET_REQUEST_KEY, false);
}
return null;
}
private boolean isDispatcherServletRequest(HttpServletRequest request) {
return request.getAttribute(
DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null;
}
}
代码逻辑简单明了:判定请求来源是不是 DispatcherServlet。并将判断结果作为参数存入 RequestContext中。
扩展:在 Spring MVC 中,在请求进入到 DispatcherServlet 中时,所有的标签会被打上标签:DispatcherServlet.class.getName() + “.CONTEXT”
Servlet30WrapperFilter
ZuulFilter 执行触发条件
public class Servlet30WrapperFilter extends ZuulFilter {
// 拦截所有请求
public boolean shouldFilter() {
return true; // TODO: only if in servlet 3.0 env
}
}
只要该过滤器开启,拦截所有请求进行过滤处理。
过滤执行逻辑
public class Servlet30WrapperFilter extends ZuulFilter {
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
if (request instanceof HttpServletRequestWrapper) {