一、Zuul获取Routes规则
在上面,我们可以看到,在配置文件中配置路由,或者注册到注册中心中,就可以获取路由配置。
那么问题来了,这是如何做到的呢?
我们带着问题,可以先看下RoutesEndPoint
这个类
RoutesEndPoint
1 | "Can be used to list the reverse proxy routes") (description = |
这里首先看到一段介绍: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 | .class) (ZuulProxyMarkerConfiguration.Marker |
可以看到,容器中有这个Bean时,自动配置才会加载,这也是我们开启EnableZuulProxy
才能使用的原因
初始化类
再往下可以清楚的看到,自动配置类向容器中添加了几个类
PreDecorationFilter
:Pre阶段FilterRibbonRoutingFilter:Route
阶段FilterSimpleHostRoutingFilter
:URL请求转发时使用的Filter
继承父类Server
还有一个重点extends ZuulServerAutoConfiguration
,即扩展了父类,所以我们再到父类一看
ZuulServerAutoConfiguration
1 |
|
这个类的重点,自动装配了
ZuulController
ZuulHandlerMapping
ZuulServlet
这几个类都是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()