一、Zuul获取Routes规则
在上面,我们可以看到,在配置文件中配置路由,或者注册到注册中心中,就可以获取路由配置。
那么问题来了,这是如何做到的呢?
我们带着问题,可以先看下RoutesEndPoint这个类
RoutesEndPoint
1 | (description = "Can be used to list the reverse proxy routes") |
这里首先看到一段介绍:Can be used to list the reverse proxy routes(可用于列出反向代理路由)
说明我们找对了地方,然后我们可以看到有一个@Autowired类,RouteLocator,应该是我们要找的路由类
RouteLocator
1 | public interface RouteLocator { |
这里有三个抽象方法
getIgnoredPaths:获取被忽略的路由getRoutes:获取所有路由getMatchingRoute:获取匹配的路由
紧接着我们找他的实现类DiscoveryClientRouteLocator
DiscoveryClientRouteLocator
1 | public class DiscoveryClientRouteLocator extends SimpleRouteLocator |
这里有个locateRoutes重要方法,在第7行我们可以看到

1 | protected Map<String, ZuulRoute> locateRoutes() { |
首先获取本地配置中的路由,locateRoutes,然后循环将静态服务保存起来,这里的静态服务,其实就是我们在配置文件中配置的那些静态配置。
接着在第20行

通过注释也可以得知,添加所有在注册中心上的服务,即将Eureka上的服务也添加到路由List中去。
所以,大致就是通过这个方法,将配置和注册中心中的服务通通存储到List里,这里需要注意的是List是LinkedArrayList,即有序插入,所以我们在刚刚看routes节点的时候,配置文件中的排在前面,服务排在后面
二、Zuul请求的生命周期
这里我们先放一张官方图(Zuul1.x)

对于请求会经过pre - routing - post,其实就是过滤器,前置方法,执行方法,后置方法。
这里使用到的过滤器是ZuulServlet
ZuulServlet
ZuulServlet定义了对zuul整个过程的处理,如下:
1 | public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException { |
Pre阶段
前置阶段是由 PreDecorationFilter过滤器来寻找路由规则:

如图,getMatchingRoute()就是我们上一节说到的,在RouteLocator中的方法,获取匹配的路由
Routing阶段
RibbonRoutingFilter真正的对服务发起请求,并得到响应结果
1 |
|
通过run方法,可以看到调用了forward方法
1 | protected ClientHttpResponse forward(RibbonCommandContext context) throws Exception { |
这里可以看到,通过工厂创建出RibbonCommand,然后真正的服务调用command.execute()
接着回到run()方法中,下一行执行setResponse(response);方法
1 | protected void setResponse(ClientHttpResponse resp) |
即,将响应的内容写入到RequestContext中。
ROUTE还有两个过滤器SendForwardFilter(forward请求转发)、SimpleHostRoutingFilter(url请求转发),根据不同的路由类型匹配相应的过滤器。
Post阶段
SendResponseFilter对内容进行响应
1 |
|
还是先看run()方法,这里对于响应,核心方法是writeResponse();
1 | private void writeResponse() throws Exception { |
这里源码比较长,大致的意思就是创建一些IO类,从之前RequestContext中取出response,然后进行一系列的判断,最后将response响应。
error阶段
当PRE、ROUTE、POST阶段的过滤器发生错误时,会调用ERROR过滤器。默认的error过滤器有SendErrorFilter
三、Zuul的自动装配
看自动装配前,我们先看下我们开启的注解
@EnableZuulProxy
1 |
|
对此注解,import了ZuulProxyMarkerConfiguration:
1 |
|
可以看到,这里仅仅是往容器中添加了ZuulProxyMarkerConfiguration.Marker这个Bean
所以@EnableZuulProxy的作用就是,向容器中添加ZuulProxyMarkerConfiguration与ZuulProxyMarkerConfiguration.Marker
接着,我们要看自动装配,就肯定要找AutoConfiguration类,即ZuulProxyAutoConfiguration
ZuulProxyAutoConfiguration
1 |
|
这里几个重点代码我保留了一下,
自动装配条件
1 | (ZuulProxyMarkerConfiguration.Marker.class) |
可以看到,容器中有这个Bean时,自动配置才会加载,这也是我们开启EnableZuulProxy才能使用的原因
初始化类
再往下可以清楚的看到,自动配置类向容器中添加了几个类
PreDecorationFilter:Pre阶段FilterRibbonRoutingFilter:Route阶段FilterSimpleHostRoutingFilter:URL请求转发时使用的Filter
继承父类Server
还有一个重点extends ZuulServerAutoConfiguration,即扩展了父类,所以我们再到父类一看
ZuulServerAutoConfiguration
1 |
|
这个类的重点,自动装配了
ZuulControllerZuulHandlerMappingZuulServlet
这几个类都是Zuul的重点类
Zuul重点类
RibbonRoutingFilter
这里我们一层层向上递进,我们知道,请求时最终调用的是ZuulFilter即RibbonRoutingFilter
ZuulServlet
由第二章代码可知,是由``ZuulServlet调用的ZuulFilter的run()`方法
ZuulController

由ZuulController代码可知,ZuulServlet是由他委派
ZuulHandlerMapping
1 |
|
而在刚刚Server的自动配置类中,ZuulHandlerMapping的实例化又添加了ZuulController
DispatchServlet
最后我们开始探查ZuulHandlerMapping的lookupHandler即请求调用者



通过一步步向上探查,最后发现是DIspatchServlet的doDispatch()方法调用,这个方法我们并不陌生,就是前端控制器的请求分发方法,即SpringMVC中的类。
总结
所以最后总结一下request请求Zuul过程
- DispatchServlet —> doDispatch()
- ZuulHandlerMapping —> lookupHandler()
- ZuulController —> handleRequest()
- ZuulServlet —> service()
- ZuulFilter(RibbonRoutingFilter) —> run()
- ZuulServlet —> service()
- ZuulController —> handleRequest()
- ZuulHandlerMapping —> lookupHandler()