# 原理分析之如何路由 ## 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类中找到了定义 ```java // pre filters @Bean @ConditionalOnMissingBean(PreDecorationFilter.class) public PreDecorationFilter preDecorationFilter(RouteLocator routeLocator, ProxyRequestHelper proxyRequestHelper) { return new PreDecorationFilter(routeLocator, this.server.getServlet().getContextPath(), this.zuulProperties, proxyRequestHelper); } ``` 方法默认注入了RouteLocator类,默认注入的实现是CompositeRouteLocator类(通过打断点可以查看)。 同时方法上用了`@ConditionalOnMissingBean`注解,表示如果其它地方没有声明,则默认使用这个。 因此我们可以自己声明一个PreDecorationFilter,然后注入自定义的RouteLocator就行了。 SOP自定义的RouteLocator为:`com.gitee.sop.gatewaycommon.zuul.route.SopRouteLocator`,可自行前往查看。 然后再我们的Config中定义: ```java /** * 选取路由 * @param zuulRouteRepository * @param proxyRequestHelper * @return */ @Bean public PreDecorationFilter preDecorationFilter(ZuulRouteRepository zuulRouteRepository, ProxyRequestHelper proxyRequestHelper) { // 自定义路由 RouteLocator routeLocator = new SopRouteLocator(zuulRouteRepository); return new PreDecorationFilter(routeLocator, this.server.getServlet().getContextPath(), this.zuulProperties, proxyRequestHelper); } ``` 到此,我们只需要实现RouteLocator接口,就能使用zuul默认的路由功能,非常方便。