zuul源码学习

平常使用zuul网关,主要就是用来做路由请求,和通过过滤器做相应的增强限制处理。其实,zuul就是一组过滤器,有pre,routing,post,error不同类型的过滤器。执行的时机也不一样。而路由功能也是通过过滤器来实现的。我们来看下源码,大概了解下他是如何做的吧。

首先,老规矩还是找到spring.factories,找到自动配置的类ZuulProxyAutoConfiguration和父类ZuulServerAutoConfiguration

public class ZuulProxyAutoConfiguration extends ZuulServerAutoConfiguration {
//继承自SimpleRouteLocator,路由定位器
@Bean
	@ConditionalOnMissingBean(DiscoveryClientRouteLocator.class)
	public DiscoveryClientRouteLocator discoveryRouteLocator(
			ServiceRouteMapper serviceRouteMapper) {
		return new DiscoveryClientRouteLocator(this.server.getServlet().getContextPath(),
				this.discovery, this.zuulProperties, serviceRouteMapper,
				this.registration);
	}
	//pre 过滤器
@Bean
	@ConditionalOnMissingBean(PreDecorationFilter.class)
	public PreDecorationFilter preDecorationFilter(RouteLocator routeLocator,
			ProxyRequestHelper proxyRequestHelper) {
		return new PreDecorationFilter(routeLocator,
				this.server.getServlet().getContextPath(), this.zuulProperties,
				proxyRequestHelper);
	}
	//route过滤器
@Bean
	@ConditionalOnMissingBean(RibbonRoutingFilter.class)
	public RibbonRoutingFilter ribbonRoutingFilter(ProxyRequestHelper helper,
			RibbonCommandFactory<?> ribbonCommandFactory) {
		RibbonRoutingFilter filter = new RibbonRoutingFilter(helper, ribbonCommandFactory,
				this.requestCustomizers);
		return filter;
	}
}


public class ZuulServerAutoConfiguration {
//组合的路由定位器,将容器中的路由定位器组合一起,默认使用此路由定位器
@Bean
	@Primary
	public CompositeRouteLocator primaryRouteLocator(
			Collection<RouteLocator> routeLocators) {
		return new CompositeRouteLocator(routeLocators);
	}
//Zuul创建的一个Controller,用于将请求交由ZuulServlet处理。
@Bean
	public ZuulController zuulController() {
		return new ZuulController();
	}
//SpringMvc的HandlerMapping处理器映射器,只有被此映射器处理的请求才能出发到Zuul的后续流程
@Bean
	public ZuulHandlerMapping zuulHandlerMapping(RouteLocator routes,
			ZuulController zuulController) {
		ZuulHandlerMapping mapping = new ZuulHandlerMapping(routes, zuulController);
		mapping.setErrorController(this.errorController);
		mapping.setCorsConfigurations(getCorsConfigurations());
		return mapping;
	}
}

//zuul请求处理核心
@Bean
	@ConditionalOnMissingBean(name = "zuulServlet")
	@ConditionalOnProperty(name = "zuul.use-filter", havingValue = "false",
			matchIfMissing = true)
	public ServletRegistrationBean zuulServlet() {
		ServletRegistrationBean<ZuulServlet> servlet = new ServletRegistrationBean<>(
				new ZuulServlet(), this.zuulProperties.getServletPattern());
		// The whole point of exposing this servlet is to provide a route that doesn't
		// buffer requests.
		servlet.addInitParameter("buffer-requests", "false");
		return servlet;
	}
	//注册过滤器
@Bean
	@ConditionalOnMissingBean(name = "zuulServletFilter")
	@ConditionalOnProperty(name = "zuul.use-filter", havingValue = "true",
			matchIfMissing = false)
	public FilterRegistrationBean zuulServletFilter() {
		final FilterRegistrationBean<ZuulServletFilter> filterRegistration = new FilterRegistrationBean<>();
		filterRegistration.setUrlPatterns(
				Collections.singleton(this.zuulProperties.getServletPattern()));
		filterRegistration.setFilter(new ZuulServletFilter());
		filterRegistration.setOrder(Ordered.LOWEST_PRECEDENCE);
		// The whole point of exposing this servlet is to provide a route that doesn't
		// buffer requests.
		filterRegistration.addInitParameter("buffer-requests", "false");
		return filterRegistration;
	}

大致列了几个个人感觉比较重要的组件,功能注释都有说明。在一个请求进入spring mvc的DispatcherServlet后,首先会获取遍历handlerMapping,调用getHandler方法,而getHandler方法会调用getHandlerInternal方法去获取具体handler。我们先来看ZuulHandlerMapping的父类方法AbstractUrlHandlerMapping#getHandlerInternal

protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		request.setAttribute(LOOKUP_PATH, lookupPath);
		Object handler = lookupHandler(lookupPath, request);
		if (handler == null) {
			// We need to care for the default handler directly, since we need to
			// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
			Object rawHandler = null;
			if ("/".equals(lookupPath)) {
				rawHandler = getRootHandler();
			}
			if (rawHandler == null) {
				rawHandler = getDefaultHandler();
			}
			if (rawHandler != null) {
				// Bean name or resolved handler?
				if (rawHandler instanceof String) {
					String handlerName = (String) rawHandler;
					rawHandler = obtainApplicationContext().getBean(handlerName);
				}
				validateHandler(rawHandler, request);
				handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
			}
		}
		return handler;
	}

首先获取请求地址,调用重写的ZuulHandlerMapping#lookupHandler方法来获取匹配的handler

protected Object lookupHandler(String urlPath, HttpServletRequest request)
			throws Exception {
		if (this.errorController != null
				&& urlPath.equals(this.errorController.getErrorPath())) {
			return null;
		}
		if (isIgnoredPath(urlPath, this.routeLocator.getIgnoredPaths())) {
			return null;
		}
		RequestContext ctx = RequestContext.getCurrentContext();
		if (ctx.containsKey("forward.to")) {
			return null;
		}
		if (this.dirty) {
			synchronized (this) {
				if (this.dirty) {
					registerHandlers();
					this.dirty = false;
				}
			}
		}
		return super.lookupHandler(urlPath, request);
	}

首先判断是否是errorController的路径,是否是忽略的路径,如果都不是,则调用ZuulHandlerMapping#registerHandlers

private void registerHandlers() {
		Collection<Route> routes = this.routeLocator.getRoutes();
		if (routes.isEmpty()) {
			this.logger.warn("No routes found from RouteLocator");
		}
		else {
			for (Route route : routes) {
				registerHandler(route.getFullPath(), this.zuul);
			}
		}
	}

这个方法委托调用routeLocator的getRoutes方法获取route集合,实际调用的就是CompositeRouteLocator#getRoutes,而CompositeRouteLocator是个路由定位器的组合,会遍历所有的路由定位器,调用SimpleRouteLocator#getRoutes

public List<Route> getRoutes() {
		List<Route> values = new ArrayList<>();
		for (Entry<String, ZuulRoute> entry : getRoutesMap().entrySet()) {
			ZuulRoute route = entry.getValue();
			String path = route.getPath();
			try {
				values.add(getRoute(route, path));
			}
			catch (Exception e) {
				if (log.isWarnEnabled()) {
					log.warn("Invalid route, routeId: " + route.getId()
							+ ", routeServiceId: " + route.getServiceId() + ", msg: "
							+ e.getMessage());
				}
				if (log.isDebugEnabled()) {
					log.debug("", e);
				}
			}
		}
		return values;
	}

先跟进getRoutesMap方法

protected Map<String, ZuulRoute> getRoutesMap() {
		if (this.routes.get() == null) {
			this.routes.set(locateRoutes());
		}
		return this.routes.get();
	}

locateRoutes方法会调用子类DiscoveryClientRouteLocator#locateRoutes

protected LinkedHashMap<String, ZuulRoute> locateRoutes() {
		LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<>();
		//调用父类将配置的路由放入map,Path为key
		routesMap.putAll(super.locateRoutes());
		if (this.discovery != null) {
			Map<String, ZuulRoute> staticServices = new LinkedHashMap<>();
			for (ZuulRoute route : routesMap.values()) {
				String serviceId = route.getServiceId();
				if (serviceId == null) {
					serviceId = route.getId();
				}
				if (serviceId != null) {
					staticServices.put(serviceId, route);
				}
			}
			// 通过注册中心获取所有服务id
			List<String> services = this.discovery.getServices();
			//获取忽略列表
			String[] ignored = this.properties.getIgnoredServices()
					.toArray(new String[0]);
					//遍历所有注册的服务id,将拼接路径path/服务id/**放入map
			for (String serviceId : services) {
				// Ignore specifically ignored services and those that were manually
				// configured
				String key = "/" + mapRouteToService(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);
					}
				}
				if (!PatternMatchUtils.simpleMatch(ignored, serviceId)
						&& !routesMap.containsKey(key)) {
					// Not ignored
					routesMap.put(key, new ZuulRoute(key, serviceId));
				}
			}
		}
		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);
		}
		LinkedHashMap<String, ZuulRoute> values = new LinkedHashMap<>();
		//处理Prefix
		for (Entry<String, ZuulRoute> entry : routesMap.entrySet()) {
			String path = entry.getKey();
			// Prepend with slash if not already present.
			if (!path.startsWith("/")) {
				path = "/" + path;
			}
			if (StringUtils.hasText(this.properties.getPrefix())) {
				path = this.properties.getPrefix() + path;
				if (!path.startsWith("/")) {
					path = "/" + path;
				}
			}
			values.put(path, entry.getValue());
		}
		return values;
	}

首先会调用父类将配置的路由信息放入map,Path为key,route为value,然后遍历通过注册中心获取所有服务id,拼接key/服务id/**,并将其作为path放入map。获取完route集合后,回到ZuulHandlerMapping#registerHandlers方法,接下来遍历所有route,注册到handlerMap,
路径为key,ZuulController为值。

for (Route route : routes) {
				registerHandler(route.getFullPath(), this.zuul);
			}

注册完之后,ZuulHandlerMapping#lookupHandler方法会调用父类的lookupHandler方法,根据url从handlerMap中拿到对应handler也就是ZuulController具体看AbstractUrlHandlerMapping#lookupHandler

protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
		// Direct match?
		Object handler = this.handlerMap.get(urlPath);
		...
		}

如果url匹配,会进入zuul执行流程,执行ZuulController#handleRequest方法

public ModelAndView handleRequest(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		try {
			// We don't care about the other features of the base class, just want to
			// handle the request
			return super.handleRequestInternal(request, response);
		}
		finally {
			// @see com.netflix.zuul.context.ContextLifecycleFilter.doFilter
			RequestContext.getCurrentContext().unset();
		}
	}
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
			throws Exception {

		Assert.state(this.servletInstance != null, "No Servlet instance");
		this.servletInstance.service(request, response);
		return null;
	}

servletInstance实际就是ZuulServlet,在afterPropertiesSet方法中初始化的。所以,这里实际会调用ZuulServlet#service

public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {
        try {
       // 获取当前的请求上下文
            init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);

            // Marks this request as having passed through the "Zuul engine", as opposed to servlets
            // explicitly bound in web.xml, for which requests will not have the same data attached
            RequestContext context = RequestContext.getCurrentContext();
            context.setZuulEngineRan();

            try {
                preRoute();
            } catch (ZuulException e) {
                error(e);
                postRoute();
                return;
            }
            try {
                route();
            } catch (ZuulException e) {
                error(e);
                postRoute();
                return;
            }
            try {
                postRoute();
            } catch (ZuulException e) {
                error(e);
                return;
            }

        } catch (Throwable e) {
            error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName()));
        } finally {
            RequestContext.getCurrentContext().unset();
        }
    }

这里可以看出整个zuul的过滤器执行流程

  1. pre异常: pre -> error -> post
  2. route异常: pre -> route -> error -> post
  3. post异常: pre -> route -> post -> error
  4. 正常: pre -> route -> post
    为什么最后都要走post,因为post最后,才能直接给用户响应数据。
    pre:表示路由的前置过滤器链,route:表示路由的过滤器链,post:表示路由的后置过滤器链,error:表示路由错误过滤器链。
    而各种过滤器的获取执行过程是想同的zuulRunner->FilterProcessor,这里以pre举例,看FilterProcessor#preRoute
 public void preRoute() throws ZuulException {
        try {
            runFilters("pre");
        } catch (ZuulException e) {
            throw e;
        } catch (Throwable e) {
            throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_PRE_FILTER_" + e.getClass().getName());
        }
    }

最终都会调用runFilters方法

public Object runFilters(String sType) throws Throwable {
        if (RequestContext.getCurrentContext().debugRouting()) {
            Debug.addRoutingDebug("Invoking {" + sType + "} type filters");
        }
        boolean bResult = false;
        List<ZuulFilter> list = FilterLoader.getInstance().getFiltersByType(sType);
        if (list != null) {
            for (int i = 0; i < list.size(); i++) {
                ZuulFilter zuulFilter = list.get(i);
                Object result = processZuulFilter(zuulFilter);
                if (result != null && result instanceof Boolean) {
                    bResult |= ((Boolean) result);
                }
            }
        }
        return bResult;
    }

首先通过FilterLoader#getFiltersByType方法获取过滤器

public List<ZuulFilter> getFiltersByType(String filterType) {

        List<ZuulFilter> list = hashFiltersByType.get(filterType);
        if (list != null) return list;

        list = new ArrayList<ZuulFilter>();
		//获取所有过滤器
        Collection<ZuulFilter> filters = filterRegistry.getAllFilters();
        for (Iterator<ZuulFilter> iterator = filters.iterator(); iterator.hasNext(); ) {
            ZuulFilter filter = iterator.next();
            //遍历匹配
            if (filter.filterType().equals(filterType)) {
                list.add(filter);
            }
        }
        //排序
        Collections.sort(list); // sort by priority

        hashFiltersByType.putIfAbsent(filterType, list);
        return list;
    }

从filterRegistry中获取所有过滤器,遍历执行过滤器的filterType方法,这里是匹配filterType方法返回的是不是pre如果是则添加到list中,最后将过滤器排序(根据filterOrder方法返回值,越小越在前)返回。
拿到过滤器列表后,遍历执行FilterProcessor#processZuulFilter

 public Object processZuulFilter(ZuulFilter filter) throws ZuulException {

        RequestContext ctx = RequestContext.getCurrentContext();
        boolean bDebug = ctx.debugRouting();
        final String metricPrefix = "zuul.filter-";
        long execTime = 0;
        String filterName = "";
        try {
            long ltime = System.currentTimeMillis();
            filterName = filter.getClass().getSimpleName();
            
            RequestContext copy = null;
            Object o = null;
            Throwable t = null;

            if (bDebug) {
                Debug.addRoutingDebug("Filter " + filter.filterType() + " " + filter.filterOrder() + " " + filterName);
                copy = ctx.copy();
            }
            
            ZuulFilterResult result = filter.runFilter();
            ExecutionStatus s = result.getStatus();
            execTime = System.currentTimeMillis() - ltime;
            ...
            }

跟进过滤器实际执行方法ZuulFilter#runFilter

public ZuulFilterResult runFilter() {
        ZuulFilterResult zr = new ZuulFilterResult();
        if (!isFilterDisabled()) {
            if (shouldFilter()) {
                Tracer t = TracerFactory.instance().startMicroTracer("ZUUL::" + this.getClass().getSimpleName());
                try {
                    Object res = run();
                    zr = new ZuulFilterResult(res, ExecutionStatus.SUCCESS);
                } catch (Throwable e) {
                    t.setName("ZUUL::" + this.getClass().getSimpleName() + " failed");
                    zr = new ZuulFilterResult(ExecutionStatus.FAILED);
                    zr.setException(e);
                } finally {
                    t.stopAndLog();
                }
            } else {
                zr = new ZuulFilterResult(ExecutionStatus.SKIPPED);
            }
        }
        return zr;
    }

可以看到,这里会先去调用过滤器的shouldFilter方法,如果返回为true,则去调用过滤器的run方法,执行业务逻辑。我们先看默认的pre过滤器PreDecorationFilter的run方法

public Object run() {
		RequestContext ctx = RequestContext.getCurrentContext();
		final String requestURI = this.urlPathHelper
				.getPathWithinApplication(ctx.getRequest());
				// 根据请求路径获取route
		Route route = this.routeLocator.getMatchingRoute(requestURI);
		if (route != null) {
		//获取目标地址(serviceId或者url)
			String location = route.getLocation();
			if (location != null) {
				ctx.put(REQUEST_URI_KEY, route.getPath());
				ctx.put(PROXY_KEY, route.getId());
				//忽略headers信息的处理
				if (!route.isCustomSensitiveHeaders()) {
					this.proxyRequestHelper.addIgnoredHeaders(
							this.properties.getSensitiveHeaders().toArray(new String[0]));
				}
				else {
					this.proxyRequestHelper.addIgnoredHeaders(
							route.getSensitiveHeaders().toArray(new String[0]));
				}

				if (route.getRetryable() != null) {
					ctx.put(RETRYABLE_KEY, route.getRetryable());
				}
				//判断目标地址是否http开头或者https开头
				if (location.startsWith(HTTP_SCHEME + ":")
						|| location.startsWith(HTTPS_SCHEME + ":")) {
					ctx.setRouteHost(getUrl(location));
					ctx.addOriginResponseHeader(SERVICE_HEADER, location);
				}
				//是否forward:
				else if (location.startsWith(FORWARD_LOCATION_PREFIX)) {
					ctx.set(FORWARD_TO_KEY,
							StringUtils.cleanPath(
									location.substring(FORWARD_LOCATION_PREFIX.length())
											+ route.getPath()));
					ctx.setRouteHost(null);
					return null;
				}
				else {
				
					// set serviceId for use in filters.route.RibbonRequest
					ctx.set(SERVICE_ID_KEY, location);
					ctx.setRouteHost(null);
					ctx.addOriginResponseHeader(SERVICE_ID_HEADER, location);
				}
				if (this.properties.isAddProxyHeaders()) {
					addProxyHeaders(ctx, route);
					String xforwardedfor = ctx.getRequest()
							.getHeader(X_FORWARDED_FOR_HEADER);
					String remoteAddr = ctx.getRequest().getRemoteAddr();
					if (xforwardedfor == null) {
						xforwardedfor = remoteAddr;
					}
					else if (!xforwardedfor.contains(remoteAddr)) { // Prevent duplicates
						xforwardedfor += ", " + remoteAddr;
					}
					ctx.addZuulRequestHeader(X_FORWARDED_FOR_HEADER, xforwardedfor);
				}
				if (this.properties.isAddHostHeader()) {
					ctx.addZuulRequestHeader(HttpHeaders.HOST,
							toHostHeader(ctx.getRequest()));
				}
			}
		}
		else {
			log.warn("No route found for uri: " + requestURI);
			String forwardURI = getForwardUri(requestURI);

			ctx.set(FORWARD_TO_KEY, forwardURI);
		}
		return null;
	}
  • 首先会获取请求路径,调用routeLocator的getMatchingRoute方法,最终调用SimpleRouteLocator#getSimpleMatchingRoute
protected Route getSimpleMatchingRoute(final String path) {
	
		// This is called for the initialization done in getRoutesMap()
		//初始化RoutesMap
		getRoutesMap();

		//对请求路径进行处理(dispatcherServletPath,zuulServletPath处理)
		String adjustedPath = adjustPath(path);

		//从routeMap中根据路径key获取对应的ZuulRoute 
		ZuulRoute route = getZuulRoute(adjustedPath);
		//对路径prefix,StripPrefix处理
		return getRoute(route, adjustedPath);
	}

初始化RoutesMap,对请求路径进行处理,从routeMap中根据路径key获取对应的ZuulRoute,对路径prefix,StripPrefix处理。

  • 接着获取目标地址(serviceId或者url),判断是否是http或者https或者forward开头,如果都不是则
	else {
					// set serviceId for use in filters.route.RibbonRequest
					ctx.set(SERVICE_ID_KEY, location);
					ctx.setRouteHost(null);
					ctx.addOriginResponseHeader(SERVICE_ID_HEADER, location);
				}

这里设置到全局的请求上下文中,key为serviceId,值为对应目标地址。这一步将会为了接下来的route过滤器选择做准备,如果进入当前的分支,则将会调用RibbonRoutingFilter作为route过滤器,通过注册中心获取路径请求,可以看下RibbonRoutingFilter的shouldFilter

public boolean shouldFilter() {
		RequestContext ctx = RequestContext.getCurrentContext();
		return (ctx.getRouteHost() == null && ctx.get(SERVICE_ID_KEY) != null
				&& ctx.sendZuulResponse());
	}

可以看到只有当全局的请求上下文中RouteHost为空,serviceId有值时才返回true。所以我们route会走RibbonRoutingFilter的run方法

public Object run() {
		RequestContext context = RequestContext.getCurrentContext();
		this.helper.addIgnoredHeaders();
		try {
		//构建RibbonCommandContext
			RibbonCommandContext commandContext = buildCommandContext(context);
			ClientHttpResponse response = forward(commandContext);
			//设置Response
			setResponse(response);
			return response;
		}
		catch (ZuulException ex) {
			throw new ZuulRuntimeException(ex);
		}
		catch (Exception ex) {
			throw new ZuulRuntimeException(ex);
		}
	}

构建RibbonCommandContext,调用RibbonRoutingFilter#forward方法发送请求

protected ClientHttpResponse forward(RibbonCommandContext context) throws Exception {
		Map<String, Object> info = this.helper.debug(context.getMethod(),
				context.getUri(), context.getHeaders(), context.getParams(),
				context.getRequestEntity());

//构建HttpClientRibbonCommand 
		RibbonCommand command = this.ribbonCommandFactory.create(context);
		try {
			ClientHttpResponse response = command.execute();
			this.helper.appendDebug(info, response.getRawStatusCode(),
					response.getHeaders());
			return response;
		}
		catch (HystrixRuntimeException ex) {
			return handleException(info, ex);
		}

	}

构建HttpClientRibbonCommand,然后调用HystrixCommand#execute方法执行实际请求

 public R execute() {
        try {
            return queue().get();
        } catch (Exception e) {
            throw Exceptions.sneakyThrow(decomposeException(e));
        }
    }

这一步就是ribbon的调用了。设置调用获取到的response。再来看post过滤器,默认是SendResponseFilter

	public Object run() {
		try {
		//添加响应头
			addResponseHeaders();
			//向客户端写数据
			writeResponse();
		}
		catch (Exception ex) {
			ReflectionUtils.rethrowRuntimeException(ex);
		}
		return null;
	}

这个过滤器主要将调用返回的response写到客户端。

小结

  1. zuul通过注入ZuulHandlerMapping处理器映射器,路径如果在handlerMap中(会从routeLocator里取出所有的route(路径key为配置的路由路径或者是注册在注册中心的所有服务id/*),一个一个注册到handlerMap)。会走ZuulController,而ZuulController会将请求委托给ZuulServlet的service方法处理.
  2. ZuulServlet中就是进行了不同过滤器的调用执行,正常流程为pre -> route -> post,如果有异常则error,error后如果post没有执行也会继续走post,因为需要post过滤器将最终结果返回出去。
  3. 而请求路由的功能则是由pre和route过滤器进行的。在PreDecorationFilter中,主要解析url地址,获取到当前要使用的是哪个 route,如果是route中设置的是serviceId走ribbon,会设置一个serviceId的key,这会决定使用哪个route过滤器。
  4. 由于,我们在pre过滤器中设置了serviceId的key,所以符合route过滤器RibbonRoutingFilter,而在RibbonRoutingFilter中会构建构建HttpClientRibbonCommand,去调用ribbon执行具体请求。
  5. 在post过滤器默认SendResponseFilter中会向客户端写执行返回的response。
    所以我们可以设置自定义的RouteLocator,来设置我们想要的handlerMap,决定哪些请求是走zuul的。并且自定义pre过滤器(禁用PreDecorationFilter),解析url,用自定义的逻辑来获取serviceId决定使用哪个route过滤器。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值