原理分析之如何路由

zuul如何路由

SOP网关默认使用zuul,当然也默认使用了zuul提供的路由功能。zuul默认使用过滤器来实现路由转发,我们看下zuul中自带的过滤器:

类型 顺序 过滤器 功能
pre -3 ServletDetectionFilter 标记处理 Servlet 的类型
pre -2 Servlet30WrapperFilter 包装 HttpServletRequest 请求
pre -1 FormBodyWrapperFilter 包装请求体
pre 1 DebugFilter 标记调试标志
pre 5 PreDecorationFilter 决定路由转发过滤器
route 10 RibbonRoutingFilter serviceId 请求转发
route 100 SimpleHostRoutingFilter url 请求转发
route 500 SendForwardFilter forward 请求转发
post 0 SendErrorFilter 处理有错误的请求响应
post 1000 SendResponseFilter 处理正常的请求响应

上图就是zuul提供的默认过滤器,可在org.springframework.cloud.netflix.zuul.filters下查看。

zuul的过滤器顺序值小的优先执行,其中的PreDecorationFilter是我们重点关注的类,由它来决定路由转发去向。

打开PreDecorationFilter类,看到类注释有一句话:that determines where and how to route based on the supplied

翻译过来就是说,决定从哪里获取路由,然后怎样去路由。

PreDecorationFilter类的核心方法是run()方法。找到run方法中这一句代码:

Route route = this.routeLocator.getMatchingRoute(requestURI);

这句代码很重要,表示路由从哪里获取,如果我们能够重写getMatchingRoute方法那就可以返回自己定义的路由了。

接下来找到RouteLocator类的定义,发现是通过构造方法传进来的,那么我们就去找使用构造方法的类。(IDEA下右键构造方法—Find Usage)

在org.springframework.cloud.netflix.zuul.ZuulProxyAutoConfiguration类中找到了定义

  1. // pre filters
  2. @Bean
  3. @ConditionalOnMissingBean(PreDecorationFilter.class)
  4. public PreDecorationFilter preDecorationFilter(RouteLocator routeLocator, ProxyRequestHelper proxyRequestHelper) {
  5. return new PreDecorationFilter(routeLocator, this.server.getServlet().getContextPath(), this.zuulProperties,
  6. proxyRequestHelper);
  7. }

方法默认注入了RouteLocator类,默认注入的实现是CompositeRouteLocator类(通过打断点可以查看)。

同时方法上用了@ConditionalOnMissingBean注解,表示如果其它地方没有声明,则默认使用这个。

因此我们可以自己声明一个PreDecorationFilter,然后注入自定义的RouteLocator就行了。

SOP自定义的RouteLocator为:com.gitee.sop.gatewaycommon.zuul.route.SopRouteLocator,可自行前往查看。

然后再我们的Config中定义:

  1. /**
  2. * 选取路由
  3. * @param zuulRouteRepository
  4. * @param proxyRequestHelper
  5. * @return
  6. */
  7. @Bean
  8. public PreDecorationFilter preDecorationFilter(ZuulRouteRepository zuulRouteRepository, ProxyRequestHelper proxyRequestHelper) {
  9. // 自定义路由
  10. RouteLocator routeLocator = new SopRouteLocator(zuulRouteRepository);
  11. return new PreDecorationFilter(routeLocator,
  12. this.server.getServlet().getContextPath(),
  13. this.zuulProperties,
  14. proxyRequestHelper);
  15. }

到此,我们只需要实现RouteLocator接口,就能使用zuul默认的路由功能,非常方便。