如果使用了微服务的springcloud中间件,可能前期早些时候的项目还是在使用zuul,后期的项目基本都要是选择了gateway,但是这里还是想理一理这个zull的流程,毕竟是一个开创网关先补补祖。
我们知道,HTTP请求是受HttpServlet接收的,早期项目中其实也是由HttpServlet的doGet doPost方法接收请求进行初始处理并且进行相关逻辑处理。那个年代的项目写到真是想吐。
而zuul是继承了这个HttpServlet,之后便是通过相关的type获取要执行的filter通过遍历方式执行run
另外,我们需了解继承一个类后执行重写的方法是怎么执行的。
public interface ITestFilter {
void run();
}
public abstract class TestFex implements ITestFilter{
public void runFilter(){
run();
}
}
public class TestFilteImpl extends TestFex {
@Override
public void run() {
System.out.println("=========sub test=======");
}
}
通过上面的代码,当我们进行以下方法创建与调用时,那么子类的run()就会被执行。
public class TestDemo {
public static void main(String[] args) {
TestFilteImpl testFilte = new TestFilteImpl();
TestFex testFex = new TestFex() {
@Override
public void run() {
}
};
testFilte.runFilter();
}
}
留意到上面的代码,testFilte.runFilter();,但是子类没有具体的实现,而执行此方法是回到父类去执行的,而父类又执行了run(),此时的run()是子类的。即体现了父类没有相关的方法时,则执行的是子类的(实现同一接口的方法)
zuul的Filter执行连正是通过这种方式去完成各个过滤器的调用逻辑与处理的。
DispatcherServlet作为请求分发器,Zuul集成了MVC,所以请求与SpringMvc一样,也是受DispatcherServlet分发的
负责[初始化ZuulController RouteLocator,根据URL去配置相关的映射,
public ZuulHandlerMapping(RouteLocator routeLocator, ZuulController zuul) {
this.routeLocator = routeLocator;
this.zuul = zuul;
setOrder(-200);
}
负责初始化ZuulServlet
public ZuulController() {
setServletClass(ZuulServlet.class);
setServletName("zuul");
setSupportedMethods((String[]) null); // Allow all
}
从类定义,可以看出继承关系。请求来了就进入到service方法。
总体走向是init --> preRoute() -->route(); -->postRoute();,当然这里不考虑异常情况,下面的分析是以preRoute()来说明,其他的是相似或者可以说就是一样的。
public class ZuulServlet extends HttpServlet
@Override
public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {
try {
init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
// Marks this request as having passed through the "Zuul engine", as opposed to servlets
// explicitly bound in web.xml, for which requests will not have the same data attached
RequestContext context = RequestContext.getCurrentContext();
context.setZuulEngineRan();
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;
}
} catch (Throwable e) {
error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName()));
} finally {
RequestContext.getCurrentContext().unset();
}
}
RequestContext context = RequestContext.getCurrentContext();
上面是通过threadlocal设置的上下文,所以说一次请求的上下文不会受并发影响就是这个原因。
1、进入此方法即调用zuulRunner的preRoute()
void preRoute() throws ZuulException {
zuulRunner.preRoute();
}
2、进入zuulRunner的preRoute即是从当前FilterProcessor获取这一前辍的Filter实例与执行
public void preRoute() throws ZuulException {
FilterProcessor.getInstance().preRoute();
}
3、根据pre获取这一类型的Filter并执行
public void preRoute() throws ZuulException {
try {
runFilters("pre");
} catch (ZuulException e) {
throw e;
} catch (Throwable e) {
throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_PRE_FILTER_" + e.getClass().getName());
}
}
4、进入runFilters(“pre”);
根据pre获取所有的pre类型的Filter
List<ZuulFilter> list = FilterLoader.getInstance().getFiltersByType(sType);
5、从中选取为pre的Filter存放到List并返回
public List<ZuulFilter> getFiltersByType(String filterType) {
List<ZuulFilter> list = hashFiltersByType.get(filterType);
if (list != null) return list;
list = new ArrayList<ZuulFilter>();
//从已经注册的Filter中获取pre类型的Filter
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;
}
6、处理返回的List,留意processZuulFilter
通过遍历,执行相关的Filter,入口是processZuulFilter(zuulFilter);
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);
}
}
7、以下简要讲主要执行的代码
public Object processZuulFilter(ZuulFilter filter) throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
ZuulFilterResult result = filter.runFilter();
}
8、进入调用子类的shouldFilter(),返回true时则再执行run()
public ZuulFilterResult runFilter() {
ZuulFilterResult zr = new ZuulFilterResult();
if (!isFilterDisabled()) {
if (shouldFilter()) {
Tracer t = TracerFactory.instance().startMicroTracer("ZUUL::" + this.getClass().getSimpleName());
try {
//以下代码就是会执行子类的run了,上面说过,父类没有则执行子类的方法,但是这里是怎么知道是哪个子类的,是在哪里处理不确定是不是上面那行代码。这里再研究。
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;
}
9、调用run即进入当前子类的run()
到此,一个zuul的处理流程已经大致说完了。
因篇幅问题不能全部显示,请点此查看更多更全内容