(二)zuul源码-Zuul组件中相关的路由过滤器
那么如何给对应的请求找到处理器?
那么在讲查找过程的时候,需要去了解一下重要的接口。
重要的接口
ZuulFilterResult
用于存储ZuulFilter的执行结果
public final class ZuulFilterResult {
private Object result;
private Throwable exception;
private ExecutionStatus status;
}
ZuulFilter
ZuulFilter过滤器接口
public interface IZuulFilter {
//判断是否要拦截
boolean shouldFilter();
//运行
Object run() throws ZuulException;
}
模板模式-核心实现。具体指定了ZuulFIlter的执行过程。
public abstract class ZuulFilter implements IZuulFilter, Comparable<ZuulFilter> {
过滤器的类型-分为pre post route error,由过滤器的子类去实现。
abstract public String filterType();
public ZuulFilterResult runFilter() {
ZuulFilterResult zr = new ZuulFilterResult();
需要开启过滤
if (!isFilterDisabled()) {
if (shouldFilter()) {
Tracer t = TracerFactory.instance().startMicroTracer("ZUUL::" + this.getClass().getSimpleName());
try {
Object res = run();
zr = new ZuulFilterResult(res, ExecutionStatus.SUCCESS);
} catch (Throwable e) {
t.setName("ZUUL::" + this.getClass().getSimpleName() + " failed");
zr = new ZuulFilterResult(ExecutionStatus.FAILED);
zr.setException(e);
} finally {
t.stopAndLog();
}
} else {
zr = new ZuulFilterResult(ExecutionStatus.SKIPPED);
}
}
return zr;
}
}
FilterRegistry
这个类很简单,就是用于过滤器注册的。
public class FilterRegistry {
private static final FilterRegistry INSTANCE = new FilterRegistry();
public static final FilterRegistry instance() {
return INSTANCE;
}
private final ConcurrentHashMap<String, ZuulFilter> filters = new ConcurrentHashMap<String, ZuulFilter>();
private FilterRegistry() {
}
public ZuulFilter remove(String key) {
return this.filters.remove(key);
}
public ZuulFilter get(String key) {
return this.filters.get(key);
}
public void put(String key, ZuulFilter filter) {
this.filters.putIfAbsent(key, filter);
}
public int size() {
return this.filters.size();
}
public Collection<ZuulFilter> getAllFilters() {
return this.filters.values();
}
}
FilterLoader
这个类其实就是用来存储过滤器以及对过滤器分类,以及加载过滤器的。
public class FilterLoader {
final static FilterLoader INSTANCE = new FilterLoader();
private final ConcurrentHashMap<String, Long> filterClassLastModified = new ConcurrentHashMap<String, Long>();
private final ConcurrentHashMap<String, String> filterClassCode = new ConcurrentHashMap<String, String>();
private final ConcurrentHashMap<String, String> filterCheck = new ConcurrentHashMap<String, String>();
private final ConcurrentHashMap<String, List<ZuulFilter>> hashFiltersByType = new ConcurrentHashMap<String, List<ZuulFilter>>();
private FilterRegistry filterRegistry = FilterRegistry.instance();
}
FilterProcessor
<span id="FilterProcessor">FilterProcessor的runFilters方法</span>
这个类就是过滤器处理器,其实zuul处理请求都是通过过滤器的形式去处理的。
最重要的地方在于定义了如何利用过滤器去执行请求。
public class FilterProcessor {
static FilterProcessor INSTANCE = new FilterProcessor();
public Object runFilters(String sType) throws Throwable {
if (RequestContext.getCurrentContext().debugRouting()) {
Debug.addRoutingDebug("Invoking {" + sType + "} type filters");
}
boolean bResult = false;
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;
}
}
1.Zuul组件如何实现动态过滤?
2.Zuul相关过滤器的注册以及作用
其实在前面已经知道,Zuul是以过滤器的方式来运行的。从FilterProcessor的runFilters方法得知代码点击此处。
那么Zuul有什么类型的过滤器?
Pre-路由前需要执行的过滤器(其实就是路由前需要做的操作)
org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter
org.springframework.cloud.netflix.zuul.filters.pre.ServletDetectionFilter
org.springframework.cloud.netflix.zuul.filters.pre.FormBodyWrapperFilter
org.springframework.cloud.netflix.zuul.filters.pre.DebugFilter
org.springframework.cloud.netflix.zuul.filters.pre.Servlet30WrapperFilter
Route-路由时执行的过滤器(其实就是路由时需要做的操作)
org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter
org.springframework.cloud.netflix.zuul.filters.route.SimpleHostRoutingFilter
org.springframework.cloud.netflix.zuul.filters.route.SendForwardFilter
Post-路由后执行的过滤器(其实就是路由后需要做的操作)
org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter
Error-发送错误时执行的过滤器
org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter
以上的过滤器的注册时机
源码如下
public class ZuulFilterInitializer {
@PostConstruct
public void contextInitialized() {
log.info("Starting filter initializer");
TracerFactory.initialize(tracerFactory);
CounterFactory.initialize(counterFactory);
for (Map.Entry<String, ZuulFilter> entry : this.filters.entrySet()) {
filterRegistry.put(entry.getKey(), entry.getValue());
}
}
}
由于最后根据类型获取的时候会进行分类以及排序(order值越小,执行的优先级越高)。最后对应的过滤器链如下
pre-org.springframework.cloud.netflix.zuul.filters.pre.ServletDetectionFilter
org.springframework.cloud.netflix.zuul.filters.pre.Servlet30WrapperFilter
org.springframework.cloud.netflix.zuul.filters.pre.FormBodyWrapperFilter
org.springframework.cloud.netflix.zuul.filters.pre.DebugFilte
org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter
route- org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter
org.springframework.cloud.netflix.zuul.filters.route.SimpleHostRoutingFilter
org.springframework.cloud.netflix.zuul.filters.route.SendForwardFilter
post- org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter
error-org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter
Route类型的过滤器的作用
由于Pre 以及 Post其实作用都很明显了,就不去了解了。因为其实最主要的是关心如何去路由。
以下是route类型的过滤器的执行顺序。
RibbonRoutingFilter
RibbonRoutingFilter的拦截方法
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
return (ctx.getRouteHost() == null && ctx.get(SERVICE_ID_KEY) != null
&& ctx.sendZuulResponse());
}
对应的路由规则
application.yml中的配置
zuul:
routes:
advice1: 随便取个名字 路由规则1
path: /client/xxx 请求路径
serviceId: client 映射到的服务Id
所以这里很清晰明了,只要RequestContext中包含service-id且没有route-host,就会被RibbonRoutingFilter拦截。
SimpleHostRoutingFilter
SimpleHostRoutingFilter的拦截方法
@Override
public boolean shouldFilter() {
return RequestContext.getCurrentContext().getRouteHost() != null
&& RequestContext.getCurrentContext().sendZuulResponse();
}
application.yml中的配置
zuul:
routes:
advice2:
path: /client/xxx
url: https://www.jianshu.com/
只要有route-host就会被SimpleHostRoutingFilter处理
SendForwardFilter
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
return ctx.containsKey(FORWARD_TO_KEY)
&& !ctx.getBoolean(SEND_FORWARD_FILTER_RAN, false);
}
配置如下
zuul:
routes:
advice3:
path: /client/xxx
url: forward:/b
路由的过程如下
对于一个请求的处理,是pre,route,post。
pre以及Post的执行过程也是一样的。只不过执行的过滤器链不一样。