一个应用网关服务,为庞大复杂的微服务系统提供统一的对外门面。
能够提供动态路由,负载均衡,统一鉴权,协议转换,监控监测等一系列功能。
Zuul自带了Ribbon和hystrix依赖,提供负载均衡和容灾支持。
Zuul的各种功能实现是基于其一系列的过滤器来实现的。
使用@EnableZuulProxy
注解开启Zuul
zuul:
routes:
<服务名>:
path: /server/url/**
serviceId: <服务名>
以上配置会对请求路径符合/server/url/**
规则的路由到对应的服务中去。
路由规则的匹配按照定义顺序进行,第一个匹配的成功返回,因此要保证有序,使用yaml代替properties文件
ZuulFilter
提供了四种类型的过滤器,分别为
Throwable
判断,调用完后还会流到post中用于返回响应对于同种类型的过滤器,order越小优先级越高,越先被调用
Zuul实现了一个ServletWrappingController
public class ZuulController extends ServletWrappingController
即包裹了一个Servlet的Controller,所有请求经过SpringMVC的DispatcherServlet
会转到这个Controller中,而这个Controller又会将请求转发到内部持有的Servlet中,即ZuulServlet
我们来看一下这个Servlet的实现,其过滤器的调用实现一目了然。
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中会RequestContext.getCurrentContext().setThrowable(e),然后调用error过滤器
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();
}
}
Route getMatchingRoute(String path)
解析请求URL为Route
例如访问http://localhost:8080/service/test
获取的Route
Route{id='service', fullPath='/service/test', path='/test', location='service', prefix='/service'}
从ZuulProperties
即配置文件中获取路由信息,是Zuul路由配置的核心
继承了SimpleRouteLocator
,能够从DiscoveryClient
中获取配置并添加到ZuulProperties
中
调用RouteLocator
的refresh()
方法,会将ZuulProperties
中的路由信息替换RouteLocator
的私有属性Map
。
Zuul提供了ZuulRefreshListener
监听刷新事件,自动调用RouteLocator
的refresh()
方法
调用RouteLocator
对路由信息进行匹配和预处理
当ServiceId不为空时使用该过滤器,根据ServiceId和Ribbon拿到具体的服务实例地址,进行转发。
当RouteHost
不为空时使用该过滤器