SpringCloudGateway动态路由(Redis持久化)以及请求到寻找路由的流程

SpringCloudGateway动态路由(Redis持久化)以及请求到寻找路由的流程

1、路由加载流程简述
/**
     * 1、处理映射器加载路由 {@link RoutePredicateHandlerMapping#lookupRoute(ServerWebExchange)}
     * 2、路由加载器获取路由 {@link RouteLocator#getRoutes()} ;{@link RouteLocator}注入到Spring容器的是统一入口{@link CachingRouteLocator},
     *    {@link CompositeRouteLocator#getRoutes()} 在 {@link GatewayAutoConfiguration#cachedCompositeRouteLocator(List)} 注入到Spring容器中,
     * 3、路由定义信息加载器 方法cachedCompositeRouteLocator 中 List<RouteLocator> routeLocators 中,
     *    其中之一{@link RouteDefinitionRouteLocator}
     *    在{@link GatewayAutoConfiguration#routeDefinitionRouteLocator(GatewayProperties, List, List,RouteDefinitionLocator, ConfigurationService)} 注入到Spring容器中,
     *    其中 {@link RouteDefinitionLocator}(路由定义信息加载器)是统一入口 {@link CompositeRouteDefinitionLocator} 在{@link GatewayAutoConfiguration#routeDefinitionLocator(List)}注入到Spring容器中,
     *    其中 List<RouteDefinitionLocator> routeDefinitionLocators 包含
     *    读取配置文件的 {@link GatewayAutoConfiguration#propertiesRouteDefinitionLocator(GatewayProperties)}
     *    不存在持久化bean的时候 {@link GatewayAutoConfiguration#inMemoryRouteDefinitionRepository()}
     * 4、加载路由定义信息 {@link RouteDefinitionLocator#getRouteDefinitions()} {@link CompositeRouteDefinitionLocator#getRouteDefinitions()} 会统一加载,所有的 RouteDefinitionLocator bean
     *
     * 流程如下 {@link RoutePredicateHandlerMapping#lookupRoute(ServerWebExchange)}
     *  {@link RouteLocator#getRoutes()} --[{@link CompositeRouteLocator#getRoutes()} {@link CachingRouteLocator#getRoutes()} 主要
     *  {@link RouteDefinitionRouteLocator#getRoutes()},初始化过滤器、断言等都在此类 ]
     *  {@link RouteDefinitionRouteLocator} 中的{@link RouteDefinitionLocator#getRouteDefinitions()}获取路由信息,{@link RouteDefinitionRouteLocator#convertToRoute(RouteDefinition)}
     *  路由信息转换为路由
     *
     *  RoutePredicateHandlerMapping 对应的映射,访问一次都会加载一次
     * @return
     */
2、动态路由,redis存储
  • Controller
@RestController
public class GatewayRouteController extends GatewayBaseController{

    @Autowired
    DynamicRouteService routeService;
    @Autowired
    GatewayAppRouteRedisRepository redisRepository;

//    @PostMapping(value = "add", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
//    public Response save(@RequestBody GatewayRouteDefinition definition) {
//        routeService.save(definition);
//        return Response.success();
//    }

    @PostMapping("route/save_or_update")
    public Mono<RestResult> update(@RequestBody GatewayAppRoute definition) {
        routeService.update(definition);
        redisRepository.update(definition);
        return Mono.just(TRestBuilder.success());
    }


    @DeleteMapping("route/{id}")
    public Mono<RestResult> delete(@PathVariable("id") String id) {
        routeService.delete(id);
        redisRepository.delete(id);
        return Mono.just(TRestBuilder.success());
    }

    @PostMapping("routes")
    public Mono<RestResult<List<GatewayAppRoute>>> list() {
        return Mono.just(TRestBuilder.success(redisRepository.routeViews()));
    }
}
  • 动态路由
/**
 * 动态路由信息
 */
public class DynamicRouteService implements ApplicationEventPublisherAware {
    @Autowired
    RouteDefinitionRepository routeDefinitionRepository;// 实现redis存储

    private ApplicationEventPublisher publisher;
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
     this.publisher=applicationEventPublisher;
    }

    // 发布事件,刷新路由,实现动态路由
    private void publish() {
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
    }

    public void save(GatewayAppRoute definition){
        RouteDefinition routeDefinition=definition.routeDefinition();
        routeDefinitionRepository.save(Mono.just(routeDefinition)).subscribe();
        publish();
    }


    public void update(GatewayAppRoute definition){
        RouteDefinition routeDefinition=definition.routeDefinition();
        routeDefinitionRepository.delete(Mono.just(definition.getServiceId()));
        routeDefinitionRepository.save(Mono.just(routeDefinition)).subscribe();
        publish();
    }


    public void delete(String serviceId){
        routeDefinitionRepository.delete(Mono.just(serviceId));
        publish();
    }
}
  • Redis持久化
/**
 * 路由存储 redis
 */
public class RouteDefinitionRedisRepository implements RouteDefinitionRepository,RouteRepository {
    final static String GATEWAY_ROUTES = "GATEWAY:ROUTE";
    @Autowired
    RedisCache redisCache;//redis操作,Redistemplate

    /**
     * 从redis加在路由信息
     * @return
     */
    public Map<String,RouteDefinition> loadRoute() {
        Map<String, RouteDefinition> data = redisCache.getCacheMap(GATEWAY_ROUTES, RouteDefinition.class);
        return data;
    }

    /**
     * 1、处理映射器加载路由 {@link RoutePredicateHandlerMapping#lookupRoute(ServerWebExchange)}
     * 2、路由加载器获取路由 {@link RouteLocator#getRoutes()} ;{@link RouteLocator}注入到Spring容器的是统一入口{@link CachingRouteLocator},
     *    {@link CompositeRouteLocator#getRoutes()} 在 {@link GatewayAutoConfiguration#cachedCompositeRouteLocator(List)} 注入到Spring容器中,
     * 3、路由定义信息加载器 方法cachedCompositeRouteLocator 中 List<RouteLocator> routeLocators 中,
     *    其中之一{@link RouteDefinitionRouteLocator}
     *    在{@link GatewayAutoConfiguration#routeDefinitionRouteLocator(GatewayProperties, List, List,RouteDefinitionLocator, ConfigurationService)} 注入到Spring容器中,
     *    其中 {@link RouteDefinitionLocator}(路由定义信息加载器)是统一入口 {@link CompositeRouteDefinitionLocator} 在{@link GatewayAutoConfiguration#routeDefinitionLocator(List)}注入到Spring容器中,
     *    其中 List<RouteDefinitionLocator> routeDefinitionLocators 包含
     *    读取配置文件的 {@link GatewayAutoConfiguration#propertiesRouteDefinitionLocator(GatewayProperties)}
     *    不存在持久化bean的时候 {@link GatewayAutoConfiguration#inMemoryRouteDefinitionRepository()}
     * 4、加载路由定义信息 {@link RouteDefinitionLocator#getRouteDefinitions()} {@link CompositeRouteDefinitionLocator#getRouteDefinitions()} 会统一加载,所有的 RouteDefinitionLocator bean
     *
     * 流程如下 {@link RoutePredicateHandlerMapping#lookupRoute(ServerWebExchange)}
     *  {@link RouteLocator#getRoutes()} --[{@link CompositeRouteLocator#getRoutes()} {@link CachingRouteLocator#getRoutes()} 主要
     *  {@link RouteDefinitionRouteLocator#getRoutes()},初始化过滤器、断言等都在此类 ]
     *  {@link RouteDefinitionRouteLocator} 中的{@link RouteDefinitionLocator#getRouteDefinitions()}获取路由信息,{@link RouteDefinitionRouteLocator#convertToRoute(RouteDefinition)}
     *  路由信息转换为路由
     *
     *  RoutePredicateHandlerMapping 对应的映射,访问一次都会加载一次
     * @return
     */
    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        List<RouteDefinition> routeDefinitions = new ArrayList<>();
        Map<String, RouteDefinition> data = loadRoute();
        if (!CollectionUtils.isEmpty(data)) {
            data.forEach((K, V) -> routeDefinitions.add(V));
        }
        return Flux.fromIterable(routeDefinitions);
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return route.flatMap(routeDefinition -> {
            redisCache.putDataToCacheMap(GATEWAY_ROUTES, routeDefinition.getId(), routeDefinition);
            return Mono.empty();
        });
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return routeId.flatMap(id -> {
            if (redisCache.cacheMapHasKey(GATEWAY_ROUTES, id)) {
                redisCache.deleteDataFromCacheMap(GATEWAY_ROUTES, id);
                return Mono.empty();
            }
            return Mono.defer(() -> Mono.error(new NotFoundException("RouteDefinition not found: " + routeId)));
        });
    }

    @Override
    public List<RouteDefinition> loadRoutes() {
        Map<String,RouteDefinition> data=loadRoute();
        return CollectionUtils.isEmpty(data)?new ArrayList<>():new ArrayList<>(data.values());
    }
}

  • GatewayAppRoute
/**
 * APP 配置信息
 */
@Data
public class GatewayAppRoute {
    /**
     * 服务状态
     */
    private int serviceStatus;
    /**
     * 服务名称
     */
    @NotBlank(message = "serviceName不能为空")
    private String serviceName;
    /**
     * 服务版本号
     */
    @NotBlank(message = "serviceVersion不能为空")
    private String serviceVersion;
    /**
     * 路由ID(服务ID)
     */
    @NotBlank(message = "serviceId不能为空")
    private String serviceId;
    /**
     * 路由断言集合配置
     */
    @NotEmpty(message = "predicates不能为空")
    private List<GatewayDefinition> predicates = new ArrayList<>();
    /**
     * 路由过滤器集合配置
     */
    private List<GatewayDefinition> filters = new ArrayList<>();
    /**
     * 路由规则转发的目标uri
     *
     * 建议lb协议<lb://serviceId>
     */
    @NotBlank(message = "uri不能为空")
    private String uri;
    /**
     * 路由执行顺序
     */
    private int order = 0;

    @Data
    public static class GatewayDefinition {
        //断言(过滤器)对应的Name
        private String name;
        //配置的断言(过滤器)规则
        private Map<String,String> args=new LinkedHashMap<>();
    }

    public RouteDefinition routeDefinition(){
        RouteDefinition routeDefinition=new RouteDefinition();
        routeDefinition.setId(serviceId);
        routeDefinition.setOrder(order);
        URI routeUri = !StringUtils.startsWith(uri,"lb")?UriComponentsBuilder.fromHttpUrl(uri).build().toUri():URI.create(uri);
        routeDefinition.setUri(routeUri);
        if(!CollectionUtils.isEmpty(filters)){
            routeDefinition.setFilters(filters.stream().map(f->{
                FilterDefinition filterDefinition=new FilterDefinition();
                filterDefinition.setName(f.name);
                filterDefinition.setArgs(f.args);
                return filterDefinition;
            }).collect(Collectors.toList()));
        }
        if(!CollectionUtils.isEmpty(predicates)){
            routeDefinition.setPredicates(predicates.stream().map(f->{
                PredicateDefinition predicateDefinition=new PredicateDefinition();
                predicateDefinition.setName(f.name);
                predicateDefinition.setArgs(f.args);
                return predicateDefinition;
            }).collect(Collectors.toList()));
        }
        return routeDefinition;
    }
}
3. SpringCloudGateway 请求到寻找路由的流程
DispatcherHandler
package org.springframework.web.reactive;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.http.HttpStatus;
import org.springframework.lang.Nullable;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebHandler;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;

/**
 * Central dispatcher for HTTP request handlers/controllers. Dispatches to
 * registered handlers for processing a request, providing convenient mapping
 * facilities.
 *
 * <p>{@code DispatcherHandler} discovers the delegate components it needs from
 * Spring configuration. It detects the following in the application context:
 * <ul>
 * <li>{@link HandlerMapping} -- map requests to handler objects
 * <li>{@link HandlerAdapter} -- for using any handler interface
 * <li>{@link HandlerResultHandler} -- process handler return values
 * </ul>
 *
 * <p>{@code DispatcherHandler} is also designed to be a Spring bean itself and
 * implements {@link ApplicationContextAware} for access to the context it runs
 * in. If {@code DispatcherHandler} is declared with the bean name "webHandler"
 * it is discovered by {@link WebHttpHandlerBuilder#applicationContext} which
 * creates a processing chain together with {@code WebFilter},
 * {@code WebExceptionHandler} and others.
 *
 * <p>A {@code DispatcherHandler} bean declaration is included in
 * {@link org.springframework.web.reactive.config.EnableWebFlux @EnableWebFlux}
 * configuration.
 *
 * @author Rossen Stoyanchev
 * @author Sebastien Deleuze
 * @author Juergen Hoeller
 * @since 5.0
 * @see WebHttpHandlerBuilder#applicationContext(ApplicationContext)
 */
public class DispatcherHandler implements WebHandler, ApplicationContextAware {

	@Nullable
	private List<HandlerMapping> handlerMappings;

	@Nullable
	private List<HandlerAdapter> handlerAdapters;

	@Nullable
	private List<HandlerResultHandler> resultHandlers;


	/**
	 * Create a new {@code DispatcherHandler} which needs to be configured with
	 * an {@link ApplicationContext} through {@link #setApplicationContext}.
	 */
	public DispatcherHandler() {
	}

	/**
	 * Create a new {@code DispatcherHandler} for the given {@link ApplicationContext}.
	 * @param applicationContext the application context to find the handler beans in
	 */
	public DispatcherHandler(ApplicationContext applicationContext) {
		initStrategies(applicationContext);
	}


	/**
	 * Return all {@link HandlerMapping} beans detected by type in the
	 * {@link #setApplicationContext injected context} and also
	 * {@link AnnotationAwareOrderComparator#sort(List) sorted}.
	 * <p><strong>Note:</strong> This method may return {@code null} if invoked
	 * prior to {@link #setApplicationContext(ApplicationContext)}.
	 * @return immutable list with the configured mappings or {@code null}
	 */
	@Nullable
	public final List<HandlerMapping> getHandlerMappings() {
		return this.handlerMappings;
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) {
		initStrategies(applicationContext);
	}

    // 初始化处理
	protected void initStrategies(ApplicationContext context) {
		Map<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
				context, HandlerMapping.class, true, false);

		ArrayList<HandlerMapping> mappings = new ArrayList<>(mappingBeans.values());
		AnnotationAwareOrderComparator.sort(mappings);
		this.handlerMappings = Collections.unmodifiableList(mappings);

		Map<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
				context, HandlerAdapter.class, true, false);

		this.handlerAdapters = new ArrayList<>(adapterBeans.values());
		AnnotationAwareOrderComparator.sort(this.handlerAdapters);

		Map<String, HandlerResultHandler> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
				context, HandlerResultHandler.class, true, false);

		this.resultHandlers = new ArrayList<>(beans.values());
		AnnotationAwareOrderComparator.sort(this.resultHandlers);
	}


    // 获取映射处理器
	@Override
	public Mono<Void> handle(ServerWebExchange exchange) {
		if (this.handlerMappings == null) {
			return createNotFoundError();
		}
		return Flux.fromIterable(this.handlerMappings)
                 // 获取处理器,与已经注册好了的HandlerAdapter一一匹配
                 // org.springframework.web.reactive.handler.AbstractHandlerMapping#getHandler
                 //AbstractHandlerMapping 有多个子类,子类都会进入父类getHandler 
				.concatMap(mapping -> mapping.getHandler(exchange))
				.next()
				.switchIfEmpty(createNotFoundError())
                  // 执行
				.flatMap(handler -> invokeHandler(exchange, handler))
                  // 结果处理
				.flatMap(result -> handleResult(exchange, result));
	}

	private <R> Mono<R> createNotFoundError() {
		return Mono.defer(() -> {
			Exception ex = new ResponseStatusException(HttpStatus.NOT_FOUND, "No matching handler");
			return Mono.error(ex);
		});
	}
    // 看哪一种HandlerAdapter是支持该controller类型的
	private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
		if (this.handlerAdapters != null) {
			for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
				if (handlerAdapter.supports(handler)) {
					return handlerAdapter.handle(exchange, handler);
				}
			}
		}
		return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
	}

	private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
		return getResultHandler(result).handleResult(exchange, result)
				.checkpoint("Handler " + result.getHandler() + " [DispatcherHandler]")
				.onErrorResume(ex ->
						result.applyExceptionHandler(ex).flatMap(exResult -> {
							String text = "Exception handler " + exResult.getHandler() +
									", error=\"" + ex.getMessage() + "\" [DispatcherHandler]";
							return getResultHandler(exResult).handleResult(exchange, exResult).checkpoint(text);
						}));
	}

	private HandlerResultHandler getResultHandler(HandlerResult handlerResult) {
		if (this.resultHandlers != null) {
			for (HandlerResultHandler resultHandler : this.resultHandlers) {
				if (resultHandler.supports(handlerResult)) {
					return resultHandler;
				}
			}
		}
		throw new IllegalStateException("No HandlerResultHandler for " + handlerResult.getReturnValue());
	}

}

其中 org.springframework.web.reactive.DispatcherHandler#handle(ServerWebExchange exchange)

根据请求从handlerMappings获取对应的处理器映射,通过处理器映射,可以将web请求映射到正确的处理器(handler)上。

@Override
	public Mono<Object> getHandler(ServerWebExchange exchange) {
		return getHandlerInternal(exchange).map(handler -> {
			if (logger.isDebugEnabled()) {
				logger.debug(exchange.getLogPrefix() + "Mapped to " + handler);
			}
			ServerHttpRequest request = exchange.getRequest();
			if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
				CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(exchange) : null);
				CorsConfiguration handlerConfig = getCorsConfiguration(handler, exchange);
				config = (config != null ? config.combine(handlerConfig) : handlerConfig);
				if (!this.corsProcessor.process(config, exchange) || CorsUtils.isPreFlightRequest(request)) {
					return REQUEST_HANDLED_HANDLER;
				}
			}
			return handler;
		});
	}
/**
	 * Look up a handler for the given request, returning an empty {@code Mono}
	 * if no specific one is found. This method is called by {@link #getHandler}.
	 * <p>On CORS pre-flight requests this method should return a match not for
	 * the pre-flight request but for the expected actual request based on the URL
	 * path, the HTTP methods from the "Access-Control-Request-Method" header, and
	 * the headers from the "Access-Control-Request-Headers" header.
	 * @param exchange current exchange
	 * @return {@code Mono} for the matching handler, if any
	 */
	protected abstract Mono<?> getHandlerInternal(ServerWebExchange exchange);

在这里插入图片描述

这里,看到了gateway的RoutePredicateHandlerMapping

org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping

RoutePredicateHandlerMapping

org.springframework.cloud.gateway.config.GatewayAutoConfiguration 初始化

package org.springframework.cloud.gateway.handler;

import java.util.function.Function;

import reactor.core.publisher.Mono;

import org.springframework.cloud.gateway.config.GlobalCorsProperties;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.core.env.Environment;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.reactive.handler.AbstractHandlerMapping;
import org.springframework.web.server.ServerWebExchange;

import static org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping.ManagementPortType.DIFFERENT;
import static org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping.ManagementPortType.DISABLED;
import static org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping.ManagementPortType.SAME;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_HANDLER_MAPPER_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR;

/**
 * @author Spencer Gibb
 */
public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {

   private final FilteringWebHandler webHandler;
   // 路由统一加载的实例(org.springframework.cloud.gateway.route.CompositeRouteLocator)
   // org.springframework.cloud.gateway.route.CachingRouteLocator
   private final RouteLocator routeLocator;

   private final Integer managementPort;

   private final ManagementPortType managementPortType;

   public RoutePredicateHandlerMapping(FilteringWebHandler webHandler,
         RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties,
         Environment environment) {
      this.webHandler = webHandler;
      this.routeLocator = routeLocator;

      this.managementPort = getPortProperty(environment, "management.server.");
      this.managementPortType = getManagementPortType(environment);
      setOrder(1);
      setCorsConfigurations(globalCorsProperties.getCorsConfigurations());
   }

   private ManagementPortType getManagementPortType(Environment environment) {
      Integer serverPort = getPortProperty(environment, "server.");
      if (this.managementPort != null && this.managementPort < 0) {
         return DISABLED;
      }
      return ((this.managementPort == null
            || (serverPort == null && this.managementPort.equals(8080))
            || (this.managementPort != 0 && this.managementPort.equals(serverPort)))
                  ? SAME : DIFFERENT);
   }

   private static Integer getPortProperty(Environment environment, String prefix) {
      return environment.getProperty(prefix + "port", Integer.class);
   }

    // 网关路由时进入此方法
   @Override
   protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
      // don't handle requests on management port if set and different than server port
      if (this.managementPortType == DIFFERENT && this.managementPort != null
            && exchange.getRequest().getURI().getPort() == this.managementPort) {
         return Mono.empty();
      }
      exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());

       // 获取配置路由
      return lookupRoute(exchange)
            // .log("route-predicate-handler-mapping", Level.FINER) //name this
            .flatMap((Function<Route, Mono<?>>) r -> {
               exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
               if (logger.isDebugEnabled()) {
                  logger.debug(
                        "Mapping [" + getExchangeDesc(exchange) + "] to " + r);
               }

               exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
               return Mono.just(webHandler);
            }).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
               exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
               if (logger.isTraceEnabled()) {
                  logger.trace("No RouteDefinition found for ["
                        + getExchangeDesc(exchange) + "]");
               }
            })));
   }

   @Override
   protected CorsConfiguration getCorsConfiguration(Object handler,
         ServerWebExchange exchange) {
      // TODO: support cors configuration via properties on a route see gh-229
      // see RequestMappingHandlerMapping.initCorsConfiguration()
      // also see
      // https://github.com/spring-projects/spring-framework/blob/master/spring-web/src/test/java/org/springframework/web/cors/reactive/CorsWebFilterTests.java
      return super.getCorsConfiguration(handler, exchange);
   }

   // TODO: get desc from factory?
   private String getExchangeDesc(ServerWebExchange exchange) {
      StringBuilder out = new StringBuilder();
      out.append("Exchange: ");
      out.append(exchange.getRequest().getMethod());
      out.append(" ");
      out.append(exchange.getRequest().getURI());
      return out.toString();
   }

   protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
       // 获取加载路由
      return this.routeLocator.getRoutes()
            // individually filter routes so that filterWhen error delaying is not a
            // problem
            .concatMap(route -> Mono.just(route).filterWhen(r -> {
               // add the current route we are testing
               exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
               return r.getPredicate().apply(exchange);
            })
                  // instead of immediately stopping main flux due to error, log and
                  // swallow it
                  .doOnError(e -> logger.error(
                        "Error applying predicate for route: " + route.getId(),
                        e))
                  .onErrorResume(e -> Mono.empty()))
            // .defaultIfEmpty() put a static Route not found
            // or .switchIfEmpty()
            // .switchIfEmpty(Mono.<Route>empty().log("noroute"))
            .next()
            // TODO: error handling
            .map(route -> {
               if (logger.isDebugEnabled()) {
                  logger.debug("Route matched: " + route.getId());
               }
               validateRoute(route, exchange);
               return route;
            });

      /*
       * TODO: trace logging if (logger.isTraceEnabled()) {
       * logger.trace("RouteDefinition did not match: " + routeDefinition.getId()); }
       */
   }

   /**
    * Validate the given handler against the current request.
    * <p>
    * The default implementation is empty. Can be overridden in subclasses, for example
    * to enforce specific preconditions expressed in URL mappings.
    * @param route the Route object to validate
    * @param exchange current exchange
    * @throws Exception if validation failed
    */
   @SuppressWarnings("UnusedParameters")
   protected void validateRoute(Route route, ServerWebExchange exchange) {
   }

   protected String getSimpleName() {
      return "RoutePredicateHandlerMapping";
   }

   public enum ManagementPortType {

      /**
       * The management port has been disabled.
       */
      DISABLED,

      /**
       * The management port is the same as the server port.
       */
      SAME,

      /**
       * The management port and server port are different.
       */
      DIFFERENT;

   }

}
RouteLocator路由加载
package org.springframework.cloud.gateway.route;

import reactor.core.publisher.Flux;
/** 
 * org.springframework.cloud.gateway.route.CachingRouteLocator 缓存,有事件监听
 * org.springframework.cloud.gateway.route.CompositeRouteLocator 组合多种实现,提供统一入口
 * org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator 将路由定义信息转化为路由
 * @author Spencer Gibb
 */
// TODO: rename to Routes?
public interface RouteLocator {

   Flux<Route> getRoutes();

}

GatewayAutoConfiguration 加载代码

@Bean
public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
      List<GatewayFilterFactory> gatewayFilters,
      List<RoutePredicateFactory> predicates,
      RouteDefinitionLocator routeDefinitionLocator,
      ConfigurationService configurationService) {
   return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates,
         gatewayFilters, properties, configurationService);
}

@Bean
@Primary
@ConditionalOnMissingBean(name = "cachedCompositeRouteLocator")
// TODO: property to disable composite?
public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
   return new CachingRouteLocator(
         new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
}
  • RouteDefinitionRouteLocator
package org.springframework.cloud.gateway.route;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import reactor.core.publisher.Flux;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.event.FilterArgsEvent;
import org.springframework.cloud.gateway.event.PredicateArgsEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory;
import org.springframework.cloud.gateway.handler.AsyncPredicate;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory;
import org.springframework.cloud.gateway.support.ConfigurationService;
import org.springframework.cloud.gateway.support.HasRouteId;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.convert.ConversionService;
import org.springframework.validation.Validator;
import org.springframework.web.server.ServerWebExchange;

/**
 * {@link RouteLocator} that loads routes from a {@link RouteDefinitionLocator}.
 *
 * @author Spencer Gibb
 */
public class RouteDefinitionRouteLocator
		implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {

	/**
	 * Default filters name.
	 */
	public static final String DEFAULT_FILTERS = "defaultFilters";

	protected final Log logger = LogFactory.getLog(getClass());
     // 路由定义信息
	private final RouteDefinitionLocator routeDefinitionLocator;

	private final ConfigurationService configurationService;
    // 路由RoutePredicate工厂,配置该路由决定采取哪种路由规则,如何配置前缀就可以找到对应的实例??
	private final Map<String, RoutePredicateFactory> predicates = new LinkedHashMap<>();
    // 路由GatewayFilter工厂,配置该路由决定走哪些过滤器,如何配置前缀就可以找到对应的实例??
	private final Map<String, GatewayFilterFactory> gatewayFilterFactories = new HashMap<>();

	private final GatewayProperties gatewayProperties;

	@Deprecated
	public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
			List<RoutePredicateFactory> predicates,
			List<GatewayFilterFactory> gatewayFilterFactories,
			GatewayProperties gatewayProperties, ConversionService conversionService) {
		this.routeDefinitionLocator = routeDefinitionLocator;
		this.configurationService = new ConfigurationService();
		this.configurationService.setConversionService(conversionService);
		initFactories(predicates);
		gatewayFilterFactories.forEach(
				factory -> this.gatewayFilterFactories.put(factory.name(), factory));
		this.gatewayProperties = gatewayProperties;
	}

	public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
			List<RoutePredicateFactory> predicates,
			List<GatewayFilterFactory> gatewayFilterFactories,
			GatewayProperties gatewayProperties,
			ConfigurationService configurationService) {
		this.routeDefinitionLocator = routeDefinitionLocator;
		this.configurationService = configurationService;
        // 配置前缀就可以找到对应的实例,将容器中的bean先放到内存
		initFactories(predicates);
        // 配置前缀就可以找到对应的实例,将容器中的bean先放到内存
		gatewayFilterFactories.forEach(
				factory -> this.gatewayFilterFactories.put(factory.name(), factory));
		this.gatewayProperties = gatewayProperties;
	}

	@Override
	@Deprecated
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		if (this.configurationService.getBeanFactory() == null) {
			this.configurationService.setBeanFactory(beanFactory);
		}
	}

	@Autowired
	@Deprecated
	public void setValidator(Validator validator) {
		if (this.configurationService.getValidator() == null) {
			this.configurationService.setValidator(validator);
		}
	}

	@Override
	@Deprecated
	public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
		if (this.configurationService.getPublisher() == null) {
			this.configurationService.setApplicationEventPublisher(publisher);
		}
	}

    // 配置前缀就可以找到对应的实例,将容器中的bean先放到内存
	private void initFactories(List<RoutePredicateFactory> predicates) {
		predicates.forEach(factory -> {
			String key = factory.name();
			if (this.predicates.containsKey(key)) {
				this.logger.warn("A RoutePredicateFactory named " + key
						+ " already exists, class: " + this.predicates.get(key)
						+ ". It will be overwritten.");
			}
			this.predicates.put(key, factory);
			if (logger.isInfoEnabled()) {
				logger.info("Loaded RoutePredicateFactory [" + key + "]");
			}
		});
	}

	@Override
	public Flux<Route> getRoutes() {
        // 将路由定义信息转化成路由信息
		Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions()
				.map(this::convertToRoute);

		if (!gatewayProperties.isFailOnRouteDefinitionError()) {
			// instead of letting error bubble up, continue
			routes = routes.onErrorContinue((error, obj) -> {
				if (logger.isWarnEnabled()) {
					logger.warn("RouteDefinition id " + ((RouteDefinition) obj).getId()
							+ " will be ignored. Definition has invalid configs, "
							+ error.getMessage());
				}
			});
		}

		return routes.map(route -> {
			if (logger.isDebugEnabled()) {
				logger.debug("RouteDefinition matched: " + route.getId());
			}
			return route;
		});
	}
     
    // 转换成路由信息
	private Route convertToRoute(RouteDefinition routeDefinition) {
		AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
		List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);

		return Route.async(routeDefinition).asyncPredicate(predicate)
				.replaceFilters(gatewayFilters).build();
	}

	@SuppressWarnings("unchecked")
    // 加载路由网关过滤器
	List<GatewayFilter> loadGatewayFilters(String id,
			List<FilterDefinition> filterDefinitions) {
		ArrayList<GatewayFilter> ordered = new ArrayList<>(filterDefinitions.size());
		for (int i = 0; i < filterDefinitions.size(); i++) {
			FilterDefinition definition = filterDefinitions.get(i);
            // 获取网关过滤器工厂
			GatewayFilterFactory factory = this.gatewayFilterFactories
					.get(definition.getName());
			if (factory == null) {
				throw new IllegalArgumentException(
						"Unable to find GatewayFilterFactory with name "
								+ definition.getName());
			}
			if (logger.isDebugEnabled()) {
				logger.debug("RouteDefinition " + id + " applying filter "
						+ definition.getArgs() + " to " + definition.getName());
			}

			// @formatter:off
            // 构造每个工厂里对应的config信息
			Object configuration = this.configurationService.with(factory)
					.name(definition.getName())
					.properties(definition.getArgs())
					.eventFunction((bound, properties) -> new FilterArgsEvent(
							// TODO: why explicit cast needed or java compile fails
							RouteDefinitionRouteLocator.this, id, (Map<String, Object>) properties))
					.bind();
			// @formatter:on

			// some filters require routeId
			// TODO: is there a better place to apply this?
			if (configuration instanceof HasRouteId) {
				HasRouteId hasRouteId = (HasRouteId) configuration;
				hasRouteId.setRouteId(id);
			}
             // 获取过滤器是实例
			GatewayFilter gatewayFilter = factory.apply(configuration);
			if (gatewayFilter instanceof Ordered) {
				ordered.add(gatewayFilter);
			}
			else {
				ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));
			}
		}

		return ordered;
	}
    // 获取过滤器,并根据ordered决定加载顺序
	private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) {
		List<GatewayFilter> filters = new ArrayList<>();

		// TODO: support option to apply defaults after route specific filters?
		if (!this.gatewayProperties.getDefaultFilters().isEmpty()) {
			filters.addAll(loadGatewayFilters(DEFAULT_FILTERS,
					new ArrayList<>(this.gatewayProperties.getDefaultFilters())));
		}

		if (!routeDefinition.getFilters().isEmpty()) {
			filters.addAll(loadGatewayFilters(routeDefinition.getId(),
					new ArrayList<>(routeDefinition.getFilters())));
		}

		AnnotationAwareOrderComparator.sort(filters);
		return filters;
	}

	private AsyncPredicate<ServerWebExchange> combinePredicates(
			RouteDefinition routeDefinition) {
		List<PredicateDefinition> predicates = routeDefinition.getPredicates();
		if (predicates == null || predicates.isEmpty()) {
			// this is a very rare case, but possible, just match all
			return AsyncPredicate.from(exchange -> true);
		}
		AsyncPredicate<ServerWebExchange> predicate = lookup(routeDefinition,
				predicates.get(0));

		for (PredicateDefinition andPredicate : predicates.subList(1,
				predicates.size())) {
			AsyncPredicate<ServerWebExchange> found = lookup(routeDefinition,
					andPredicate);
			predicate = predicate.and(found);
		}

		return predicate;
	}
    //加载断言
	@SuppressWarnings("unchecked")
	private AsyncPredicate<ServerWebExchange> lookup(RouteDefinition route,
			PredicateDefinition predicate) {
        // 获取断言工厂
		RoutePredicateFactory<Object> factory = this.predicates.get(predicate.getName());
		if (factory == null) {
			throw new IllegalArgumentException(
					"Unable to find RoutePredicateFactory with name "
							+ predicate.getName());
		}
		if (logger.isDebugEnabled()) {
			logger.debug("RouteDefinition " + route.getId() + " applying "
					+ predicate.getArgs() + " to " + predicate.getName());
		}

		// @formatter:off
		Object config = this.configurationService.with(factory)
				.name(predicate.getName())
				.properties(predicate.getArgs())
				.eventFunction((bound, properties) -> new PredicateArgsEvent(
						RouteDefinitionRouteLocator.this, route.getId(), properties))
				.bind();
		// @formatter:on
         // 转换实例信息
		return factory.applyAsync(config);
	}

}

RouteDefinition路由定义

SpringCloudGateway通过RouteDefinition来转换生成具体的路由信息。RouteDefinition的信息是怎么加载初始化到网关系统中的,主要是通过RouteDefinitionLocator(路由定义信息加载器)接口,实现RouteDefinition初始化加载

  • RouteDefinitionLocator源码
/**
 * 路由定义信息的定位器,
 * 负责读取路由配置( org.springframework.cloud.gateway.route.RouteDefinition
 * 子类实现类
 *  1.CachingRouteDefinitionLocator -RouteDefinitionLocator包装类, 缓存目标RouteDefinitionLocator 为routeDefinitions提供缓存功能
 *  2.CompositeRouteDefinitionLocator -RouteDefinitionLocator包装类,组合多种 RouteDefinitionLocator 的实现,为 routeDefinitions提供统一入口
 *  3.PropertiesRouteDefinitionLocator-从配置文件(GatewayProperties 例如,YML / Properties 等 ) 读取RouteDefinition
 *  4.DiscoveryClientRouteDefinitionLocator-从注册中心( 例如,Eureka / Consul / Zookeeper / Etcd 等 )读取RouteDefinition
 *  5.RouteDefinitionRepository-从存储器( 例如,内存 / Redis / MySQL 等 )读取RouteDefinition
 * @author Spencer Gibb
 */
public interface RouteDefinitionLocator {

    /**
     * 获取RouteDefinition
     * @return
     */
    Flux<RouteDefinition> getRouteDefinitions();
}

RouteDefinitionLocator接口有且仅有一个方法getRouteDefinitions,此方法获取RouteDefinition的核心方法,返回Flux

RouteDefinitionLocator 类图如下:

graph TD
RouteDefinitionLocator-->CachingRouteDefinitionLocator
RouteDefinitionLocator-->CompositeRouteDefinitionLocator
RouteDefinitionLocator-->PropertiesRouteDefinitionLocator
RouteDefinitionLocator-->DiscoveryClientRouteDefinitionLocator
RouteDefinitionLocator-->RouteDefinitionRepository

子类功能描述:

  • CachingRouteDefinitionLocator:RouteDefinitionLocator包装类, 缓存目标RouteDefinitionLocator 为routeDefinitions提供缓存功能
  • CompositeRouteDefinitionLocator -RouteDefinitionLocator包装类,组合多种 RouteDefinitionLocator 的实现,为 routeDefinitions提供统一入口
  • PropertiesRouteDefinitionLocator-从配置文件(GatewayProperties 例如,YML / Properties 等 ) 读取RouteDefinition
  • RouteDefinitionRepository-从存储器( 例如,内存 / Redis / MySQL 等 )读取RouteDefinition
  • DiscoveryClientRouteDefinitionLocator-从注册中心( 例如,Eureka / Consul / Zookeeper / Etcd 等
  • PropertiesRouteDefinitionLocator
/**
 * 从Properties(GatewayProperties)中加载RouteDefinition信息
 * @author Spencer Gibb
 */
public class PropertiesRouteDefinitionLocator implements RouteDefinitionLocator {

    /**
     * 从appliccation.yml中解析前缀为spring.cloud.gateway的配置
     */
    private final GatewayProperties properties;

    public PropertiesRouteDefinitionLocator(GatewayProperties properties) {
        this.properties = properties;
    }

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        return Flux.fromIterable(this.properties.getRoutes());
    }
}

PropertiesRouteDefinitionLocator很简单从GatewayProperties实例获取RouteDefinition信息

  • GatewayProperties 在GatewayProperties初始化加载文中已详细描述
  • Flux 响应式编程
  • CachingRouteDefinitionLocator
/**
 * RouteDefinitionLocator 包装实现类,实现了路由定义的本地缓存功能
 * @author Spencer Gibb
 */
public class CachingRouteDefinitionLocator implements RouteDefinitionLocator {

    /**
     * 实际路由定义定位器
     */
    private final RouteDefinitionLocator delegate;
    
    private final Flux<RouteDefinition> routeDefinitions;
    /**
     * 路由定义的本地缓存
     */
    private final Map<String, List> cache = new HashMap<>();

    public CachingRouteDefinitionLocator(RouteDefinitionLocator delegate) {
        this.delegate = delegate;
        routeDefinitions = CacheFlux.lookup(cache, "routeDefs", RouteDefinition.class)
                .onCacheMissResume(() -> this.delegate.getRouteDefinitions());

    }

}   

RouteDefinitionLocator包装类,缓存目标RouteDefinitionLocator 为routeDefinitions提供缓存功能

  • DiscoveryClientRouteDefinitionLocator
public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLocator {
    /**
     * 注册中心客户端
     */
    private final DiscoveryClient discoveryClient;
    /**
     * 本地配置信息
     */
    private final DiscoveryLocatorProperties properties;
    /**
     * 路由ID前缀
     */
    private final String routeIdPrefix;

    public DiscoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
        this.discoveryClient = discoveryClient;
        this.properties = properties;
        if (StringUtils.hasText(properties.getRouteIdPrefix())) {
            this.routeIdPrefix = properties.getRouteIdPrefix();
        } else {
            this.routeIdPrefix = this.discoveryClient.getClass().getSimpleName() + "_";
        }
    }

    /**
     * 通过注册中心查找服务组装路由定义信息
     * @return
     */
    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
     ...代码在根据注册中心查找路由详细解析

    }
}   

DiscoveryClientRouteDefinitionLocator通过调用 DiscoveryClient 获取注册在注册中心的服务列表,生成对应的 RouteDefinition 数组

  • CompositeRouteDefinitionLocator
/**
 * 组合多个 RouteDefinitionLocator 的实现,为 routeDefinitions提供统一入口
 * @author Spencer Gibb
 */
public class CompositeRouteDefinitionLocator implements RouteDefinitionLocator {

    /**
     * 所有路由定义定位器实例集合
     */
    private final Flux<RouteDefinitionLocator> delegates;

    public CompositeRouteDefinitionLocator(Flux<RouteDefinitionLocator> delegates) {
        this.delegates = delegates;
    }

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        //将各个RouteDefinitionLocator的getRouteDefinitions合并返回统一的Flux<RouteDefinition>
        return this.delegates.flatMap(RouteDefinitionLocator::getRouteDefinitions);
    }
}

CompositeRouteDefinitionLocator 的主要作用就是将各个定位器合并提供统一的getRouteDefinitions方法入口

通过子类实现具体功能可以很清晰的看到定位器加载RouteDefinition整个流程

graph TD
PropertiesRouteDefinitionLocator-->|配置文件加载初始化| CompositeRouteDefinitionLocator
RouteDefinitionRepository-->|存储器中加载初始化| CompositeRouteDefinitionLocator
DiscoveryClientRouteDefinitionLocator-->|注册中心加载初始化| CompositeRouteDefinitionLocator

最终提供通过CompositeRouteDefinitionLocator提供统一的 getRouteDefinitions方法

RouteDefinitionLocator实例的初始化在GatewayAutoConfiguration中已经完成

  • GatewayDiscoveryClientAutoConfiguration
@Configuration
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
@AutoConfigureBefore(GatewayAutoConfiguration.class)
@ConditionalOnClass({DispatcherHandler.class, DiscoveryClient.class})
@EnableConfigurationProperties
public class GatewayDiscoveryClientAutoConfiguration {

    //初始化注册中心路由定义定位器
    @Bean
    @ConditionalOnBean(DiscoveryClient.class)
    @ConditionalOnProperty(name = "spring.cloud.gateway.discovery.locator.enabled")
    public DiscoveryClientRouteDefinitionLocator discoveryClientRouteDefinitionLocator(
            DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
        return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);
    }
  • GatewayAutoConfiguration
   //初始化配置路由定义加载器
    @Bean
    @ConditionalOnMissingBean
    public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(GatewayProperties properties) {
        return new PropertiesRouteDefinitionLocator(properties);
    }

    //初始化存储路由定义加载器
    @Bean
    @ConditionalOnMissingBean(RouteDefinitionRepository.class)
    public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository() {
        return new InMemoryRouteDefinitionRepository();
    }

     //初始化聚合路由定义加载器
    @Bean
    @Primary
    public RouteDefinitionLocator routeDefinitionLocator(List<RouteDefinitionLocator> routeDefinitionLocators) {
        return new CompositeRouteDefinitionLocator(Flux.fromIterable(routeDefinitionLocators));
    }

在Spring-Cloud-Gateway初始化完成后需要的路由定义加载器已全部实例化完成,这样就为路由的加载创建完成了必要的条件。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值