一,FilterProcessor的主要成员
Zuul的内置过滤器主要有4种:pre过滤器、route过滤器、post过滤器、error过滤器。
FilterProcessor对外提供以下4个方法:
1,pre过滤器执行逻辑
preRoute()
2,route过滤器执行逻辑
route()
3,post过滤器后执行逻辑
postRoute()
4,error过滤器执行逻辑
error()
最终都会调用:
this.runFilters(type);
二,FilterProcessor.runFilters
FilterProcessor的具体实现就是:
FilterProcessor.runFilters(type);
下面我们分步来说明:
1,根据类型拿到过滤器集合
List<ZuulFilter> filters = FilterLoader.getInstance().getFiltersByteType(type);
2,遍历过滤器集合,执行过滤器逻辑
ZuulFilter zuilFilter = list.get(i);
Object result = this.processZuulFilter(zuulFilter);
这里会调用ZuulFilter.runFilter()来执行具体的过滤器处理逻辑,然后对处理结果进行一个包装,包装成ZuulFilterResult返回。ZuulFilterResult有三种情况:
SUCCESS:过滤器执行成功
FAILED:过滤器执行失败。
SKIPPED:过滤器被跳过。每个过滤器都有一个是否执行的方法shouldFilter(),这个方法定义了过滤器的执行条件。如果一个过滤器不满足执行条件,那么这个过滤器执行时就会被跳过。
三,ZuulFilter.runFilter
this.processZuulFilter()最终会调用ZuulFilter.runFilter()。
这里思考一个问题:为什么不把ZuulFilter.runFilter()的逻辑直接写在FilterProcessor类里面?
ZuulFilter.runFilter()的执行逻辑如下:
1,判断当前过滤器是否被禁用
判断当前过滤器是否被禁用,如果没有被禁用,继续执行下面的逻辑,否则直接返回。我们可以通过下面的配置项来禁用过滤器:
zuul.过滤器类名.过滤器类型.disabled
比如我们禁用DebugFilter,可以这样配置:
zuul.DebugFilter.pre.disabled=true
2,判断当前过滤器是否满足执行条件
判断当前过滤器是否满足执行条件,调用过滤器的shouldFilter()方法进行判断。如果满足执行条件,则开始执行,如果不满足执行条件,则把执行状态置为SKIPPED返回。
if (this.shouldFilter()){
// 调用过滤器的具体实现类的run()方法
Object res = this.run();
return new ZuulFilterResult(res, ExecutionStatus.SUCCESS);
} else {
// 跳过当前过滤器
return new ZuulFilterResult(res,
ExecutionStatus.SKIPPED);
}
3,进入具体的ZuulFilter实现类,执行真正的过滤器逻辑。
Object res = this.run();
这里的run()方法,是IZuulFilter接口中定义的方法,这个方法的实现有很多,Zuul定义的内置过滤器,都继承了ZuulFilter,也就是间接实现了IZuulFilter。
我们以RibbonRoutingFilter为例来看看过滤器的具体逻辑。RibbonRoutingFilter是route过滤器,执行具体的路由操作,也就是转发请求到指定的微服务。
第一步:拿到RequestContext。这个流程基本上每个过滤器都要执行,因为RequestContext是各个过滤器之间通信的一个通道。
RequestContext context = RequestContext.
getCurrentContext();
第二步:把RequestContext包装成RibbonCommandContext
RibbonCommandContext commandContext
= this.buildCommandContext(context);
第三步:调用dispatch转发请求到指定微服务。
ClientHttpResponse response =
this.forward(commandContext);
this.setResponse(response);
return response;
在this.forward(conmandContext)方法中,根据RibbonCommandContext创建RibbonCommand,然后调用RibbonCommand的execute()执行转发。
RibbonCommand command =
this.ribbonCommandFactory.create(context);
ClientHttpResponse response =
command.execute();
return response;
四,到底是谁转发了Zuul请求
RibbonCommand是一个空接口,没有定义任何方法。但是继承了HystrixExecutable<ClientHttpResponse>接口。也就是说RibbonCommand.execute()实际上就是HystrixExecutable.execute()。
RibbonCommand的实现有2个:
HystrixCommand
HystrixCollapser
这两个实现的逻辑基本相似:
return this.queue().get();
这里把请求的转发交给了线程,然后通过Future获取到线程的执行结果返回给Ribbon
总之,最终是由Hystrix负责请求的转发。
网友评论