路由映射是zuul网关的功能之一,本篇文章通过源码探索,看看它的映射规则是如何生效的。
通过对zuul过滤器的了解,定位到映射规则逻辑是有PreDecorationFilter
完成的(详细介绍可参考往期文章:springcloud zuul源码分析:内置过滤器)。
PreDecorationFilter
是一个前置装饰过滤器,它在路由之前将映射规则初始化完成,以供后续路由环节能够知道,该请求路径匹配的是哪个微服务(即serviceId)。下面我们解读一下映射规则匹配相关源码。
1. 规则匹配在什么位置?
首先,查看PreDecorationFilter
的run()
中内容,有一个路由定位器实例routeLocator
,它根据requestURI
获取它所匹配的路由实例。
这个routeLocator
是一个接口,它有3个实现类,分别为CompositeRouteLocator
,SimpleRouteLocator
,DiscoveryClientRouteLocator
,他们均实现了getIgnoredPaths()
, getRoutes()
,getMatchingRoute(String requestURI)
等3个方法。还有一个子接口RefreshableRouteLocator
,提供一个refresh()
方法,用户刷新路由规则。
该接口有一个默认的实现为CompositeRouteLocator
。下图是ZuulServerAutoConfiguration
中初始化bean,并用Primary注解指定它为默认实现。
它是一个组合路由定位器,它注入并包含了其他路由定位器实现类的实例集合。因此调用getMatchingRoute(String path)
方法会执行下图中的逻辑。它会遍历执行SimpleRouteLocator
,DiscoveryClientRouteLocator
两个实例中的该方法,直到结果不为null时返回。这里用到了组合设计模式的思想。
2. 路由映射如何生成的?
分别介绍两种定位器中的getMatchingRoute(String path)
逻辑。
- 简单路由定位器
SimpleRouteLocator
中。
在上图中看到,获取所有路由映射关系map集合,逻辑中调用了locateRoutes()
,这个方法中获取路由映射关系的思路是从this.properties.getRoutes()
中获得。如下图:
routes
是一个路径path与zuulRoute的映射map集合。ZuulProperties
,是zuul的配置类。如下图:
它的所有values的值,在application.yml中配置。取zuul.routes
下面的值。如下图:
- 客户端发现路由定位器
DiscoveryClientRouteLocator
中。
它继承了SimpleRouteLocator
,因此getRouteMap()
方法也得到了继承。
而locateRoutes()
方法进行了重写,如下图所示:
这里首先创建了一个LinkedHashMap实例routesMap
,存放路径与路由关系。将父级中的所有路由关系全部put,this.discovery.getServices()
获取注册中心中已经注册的服务。将所有服务遍历,将路由匹配路径设置为"/"+serviceId+"/**"
的格式(如下图红线1),匹配路由则是对serviceId的封装(下图红线2处)。
3. 总结
- 路由映射,首先会获取application.yml中
zuul.route
的配置,如果没有该配置,则会以所有注册中心中的服务ID(即spring.application.name的值)为映射路径。因此,zuul.route
可以自定义配置,也可以不配置,使用服务ID请求。 - zuul的默认
servlet-path
值为/zuul
,访问地址需要加上它为前缀。当然也可以通过application.yml中zuul.servlet-path
配置项进行更改。