继续上一篇,之前学习了zuul的大概源码,今天跟踪调试一下,加深印象。
首先,启动zuul模块时,会先初始化所有的filter
@Bean
public ZuulFilterInitializer zuulFilterInitializer(
CounterFactory counterFactory, TracerFactory tracerFactory) {
FilterLoader filterLoader = FilterLoader.getInstance();
FilterRegistry filterRegistry = FilterRegistry.instance();
return new ZuulFilterInitializer(this.filters, counterFactory, tracerFactory, filterLoader, filterRegistry);
}
图中是zuul默认的所有filter。
因为ZuulFilterInitializer继承了ServletContextListener,会在启动时调用其contextInitialized方法,
@Override
public void contextInitialized(ServletContextEvent sce) {
log.info("Starting filter initializer context listener");
TracerFactory.initialize(tracerFactory);
CounterFactory.initialize(counterFactory);
for (Map.Entry<String, ZuulFilter> entry : this.filters.entrySet()) {
filterRegistry.put(entry.getKey(), entry.getValue());
}
}
可见把所有的filter保存到了filterRegistry中的currentHashMap中。
程序启动起来后,访问其中一个接口,我一看到程序进入了ZuulServlet的service方法。
首选初始化上下文信息:
init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
public void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {
RequestContext ctx = RequestContext.getCurrentContext();
if (bufferRequests) {
ctx.setRequest(new HttpServletRequestWrapper(servletRequest));
} else {
ctx.setRequest(servletRequest);
}
ctx.setResponse(new HttpServletResponseWrapper(servletResponse));
}
实际调用了ZuulRunner的init方法,我们可以看到RequestContext获取currentContext的方法,是从其threadlocal对象中获取:
public static RequestContext getCurrentContext() {
if (testContext != null) return testContext;
RequestContext context = threadLocal.get();
return context;
}
这也就实现了所有的filter共享context。
然后开始按照顺序执行filter,首先是pre类型的filter,跟踪代码可以发现,是FileProcessor类根据filter类型获取所有的filter,然后循环执行。
这里我们可以看到FilterLoader为了节省查询速度,直接就按分别按类型保存了所有的filter。
private final ConcurrentHashMap<String, List<ZuulFilter>> hashFiltersByType = new ConcurrentHashMap<String, List<ZuulFilter>>();
保存的时机就是在根据类型获取filter最后:
public List<ZuulFilter> getFiltersByType(String filterType) {
List<ZuulFilter> list = hashFiltersByType.get(filterType);
if (list != null) return list;
list = new ArrayList<ZuulFilter>();
Collection<ZuulFilter> filters = filterRegistry.getAllFilters();
for (Iterator<ZuulFilter> iterator = filters.iterator(); iterator.hasNext(); ) {
ZuulFilter filter = iterator.next();
if (filter.filterType().equals(filterType)) {
list.add(filter);
}
}
Collections.sort(list); // sort by priority
hashFiltersByType.putIfAbsent(filterType, list);
return list;
}
我们可以看到,第一次执行的时候:
该对象为空,当执行完一次之后,就包含了所有的filter。
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;
}
pre是路由前执行,post是路由之后执行,error是失败之后执行,route是真正的去路由。
route的默认filter有三个:
当我们配置文件使用serviceID时,使用RibbonRouteFilter:
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
return (ctx.getRouteHost() == null && ctx.get(SERVICE_ID_KEY) != null
&& ctx.sendZuulResponse());
}
配置文件中使用url时,使用SimpleHostRoutingFilter:
public boolean shouldFilter() {
return RequestContext.getCurrentContext().getRouteHost() != null
&& RequestContext.getCurrentContext().sendZuulResponse();
}
当使用RequestDispatch时,使用SendForwardFilter:
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
return ctx.containsKey(FORWARD_TO_KEY)
&& !ctx.getBoolean(SEND_FORWARD_FILTER_RAN, false);
}
下一篇学习Ribbon