默认CompositeRouteLocator混合路由定位器的routeLocators只有一个DiscoveryClientRouteLocator,故只需分析DiscoveryClientRouteLocator#getMatchingRoute(path)
//----------DiscoveryClientRouteLocator是SimpleRouteLocator子类,其实是调用的SimpleRouteLocator##getMatchingRoute(path) @Override public Route getMatchingRoute(final String path) { return getSimpleMatchingRoute(path); } protected Route getSimpleMatchingRoute(final String path) { if (log.isDebugEnabled()) { log.debug("Finding route for path: " + path); } // routes是保存路由信息的map,如果此时还未加载,调用locateRoutes() if (this.routes.get() == null) { this.routes.set(locateRoutes()); } if (log.isDebugEnabled()) { log.debug("servletPath=" + this.dispatcherServletPath); log.debug("zuulServletPath=" + this.zuulServletPath); log.debug("RequestUtils.isDispatcherServletRequest()=" + RequestUtils.isDispatcherServletRequest()); log.debug("RequestUtils.isZuulServletRequest()=" + RequestUtils.isZuulServletRequest()); } /** * 下面的方法主要是先对path做微调 * 再根据path到routes中匹配到ZuulRoute * 最后根据 ZuulRoute 和 adjustedPath 生成 Route */ String adjustedPath = adjustPath(path); ZuulRoute route = getZuulRoute(adjustedPath); return getRoute(route, adjustedPath); }下面我们来看看locateRoutes()是如何加载静态的、已配置的路由与来自DiscoveryClient服务发现的路由的
//----------DiscoveryClientRouteLocator#locateRoutes() 服务发现路由定位器的locateRoutes() @Override protected LinkedHashMap<String, ZuulRoute> locateRoutes() { //保存ZuulRoute的LinkedHashMap LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<String, ZuulRoute>(); //调用父类SimpleRouteLocator#locateRoutes() //加载ZuulProperties中的所有配置文件中的路由信息 routesMap.putAll(super.locateRoutes()); //如果服务发现客户端discovery存在 if (this.discovery != null) { //将routesMap已经存在的配置文件中的ZuulRoute放入staticServices<serviceId, ZuulRoute> Map<String, ZuulRoute> staticServices = new LinkedHashMap<String, ZuulRoute>(); for (ZuulRoute route : routesMap.values()) { String serviceId = route.getServiceId(); //如果serviceId为null,以id作为serviceId,此情况适合 zuul.routes.xxxx=http://www.likecs.com/xxxx/** 的情况 if (serviceId == null) { serviceId = route.getId(); } if (serviceId != null) { staticServices.put(serviceId, route); } } // Add routes for discovery services by default List<String> services = this.discovery.getServices(); //到注册中心找到所有service String[] ignored = this.properties.getIgnoredServices() .toArray(new String[0]); //遍历services for (String serviceId : services) { // Ignore specifically ignored services and those that were manually // configured String key = "http://www.likecs.com/" + mapRouteToService(serviceId) + "/**"; //如果注册中心的serviceId在staticServices集合中,并且此路由没有配置URL //那么,更新路由的location为serviceId if (staticServices.containsKey(serviceId) && staticServices.get(serviceId).getUrl() == null) { // Explicitly configured with no URL, cannot be ignored // all static routes are already in routesMap // Update location using serviceId if location is null ZuulRoute staticRoute = staticServices.get(serviceId); if (!StringUtils.hasText(staticRoute.getLocation())) { staticRoute.setLocation(serviceId); } } //如果注册中心的serviceId不在忽略范围内,且routesMap中还没有包含,添加到routesMap if (!PatternMatchUtils.simpleMatch(ignored, serviceId) && !routesMap.containsKey(key)) { // Not ignored routesMap.put(key, new ZuulRoute(key, serviceId)); } } } // 如果routesMap中有 /** 的默认路由配置 if (routesMap.get(DEFAULT_ROUTE) != null) { ZuulRoute defaultRoute = routesMap.get(DEFAULT_ROUTE); // Move the defaultServiceId to the end routesMap.remove(DEFAULT_ROUTE); routesMap.put(DEFAULT_ROUTE, defaultRoute); } //将routesMap中的数据微调后,放到values<String, ZuulRoute>,返回 LinkedHashMap<String, ZuulRoute> values = new LinkedHashMap<>(); for (Entry<String, ZuulRoute> entry : routesMap.entrySet()) { String path = entry.getKey(); // Prepend with slash if not already present. if (!path.startsWith("http://www.likecs.com/")) { path = "http://www.likecs.com/" + path; } if (StringUtils.hasText(this.properties.getPrefix())) { path = this.properties.getPrefix() + path; if (!path.startsWith("http://www.likecs.com/")) { path = "http://www.likecs.com/" + path; } } values.put(path, entry.getValue()); } return values; }此方法运行后就已经加载了配置文件中所有路由信息,以及注册中心中的服务路由信息,有的通过URL路由,有的通过serviceId路由
只需根据本次请求的requestURI与 路由的pattern匹配找到对应的路由