老样子, 查看factories内配置如下
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
# 依赖包校验配置
org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration,\
# Gateway核心配置
org.springframework.cloud.gateway.config.GatewayAutoConfiguration,\
# Gateway的Hystrix断路器配置
org.springframework.cloud.gateway.config.GatewayHystrixCircuitBreakerAutoConfiguration,\
# Gateway的Resilience4J断路器配置
org.springframework.cloud.gateway.config.GatewayResilience4JCircuitBreakerAutoConfiguration,\
# gateway负载均衡客户端配置
org.springframework.cloud.gateway.config.GatewayLoadBalancerClientAutoConfiguration,\
#
org.springframework.cloud.gateway.config.GatewayNoLoadBalancerClientAutoConfiguration,\
# 路由度量配置
org.springframework.cloud.gateway.config.GatewayMetricsAutoConfiguration,\
# 流控的依赖配置信息
org.springframework.cloud.gateway.config.GatewayRedisAutoConfiguration,\
# 服务发现相关的依赖配置
org.springframework.cloud.gateway.discovery.GatewayDiscoveryClientAutoConfiguration,\
# url全局处理映射配置
org.springframework.cloud.gateway.config.SimpleUrlHandlerMappingGlobalCorsAutoConfiguration,\
#
org.springframework.cloud.gateway.config.GatewayReactiveLoadBalancerClientAutoConfiguration
#网关环境后处理器
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.cloud.gateway.config.GatewayEnvironmentPostProcessor
依赖包校验配置
配置文件 GatewayClassPathWarningAutoConfiguration.java
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(GatewayAutoConfiguration.class)
public class GatewayClassPathWarningAutoConfiguration {
private static final Log log = LogFactory
.getLog(GatewayClassPathWarningAutoConfiguration.class);
private static final String BORDER = "\n\n**********************************************************\n\n";
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(name = "org.springframework.web.servlet.DispatcherServlet")
protected static class SpringMvcFoundOnClasspathConfiguration {
public SpringMvcFoundOnClasspathConfiguration() {
log.warn(BORDER
+ "Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway at this time. "
+ "Please remove spring-boot-starter-web dependency." + BORDER);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.springframework.web.reactive.DispatcherHandler")
protected static class WebfluxMissingFromClasspathConfiguration {
public WebfluxMissingFromClasspathConfiguration() {
log.warn(BORDER + "Spring Webflux is missing from the classpath, "
+ "which is required for Spring Cloud Gateway at this time. "
+ "Please add spring-boot-starter-webflux dependency." + BORDER);
}
}
}
-
第一个校验提示 Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway at this time. Please remove spring-boot-starter-web dependency.
意思是在上下文中发现有 spring MVC的踪影(引入了 springmvc 包), 它不能与 Gateway 相容, 请移除
spring-boot-starter-web
这个依赖 -
第二个校验提示 Spring Webflux is missing from the classpath,which is required for Spring Cloud Gateway at this time. Please add spring-boot-starter-webflux dependency.
意思是在上下文中没有发现 webflux 的踪迹(没有引入 webflux包), 这个包是 gateway 必须的, 请引入
spring-boot-starter-webflux
依赖
再看 spring-cloud-gateway 源码包结构, 发现在 core 包中的 pom 文件已经包含了 webflux 文件
所以基本上不会出现第二个提示, 除非在引入 gateway 包时, 排除 webflux, 然而, 第一个提示却是时有发生, 但这是不应该的, 因为 gateway 本身就不是一个业务模块, 这个模块中, 不应该存有接收其它你需要的业务的功能, 如果实在必要, 也可以使用 webflux 接收请求, 而且可以扩大请求量
总结:
- gateway依赖webflux, 所以 gateway 是通过 netty 容器启动的, 协议是 socket
- gateway 与 springmvc 不兼容, 但不表示 webflux 与 springMVC 不兼容
- 对于熟悉 springMVC 的人都知道它是基于
org.springframework.web.servlet.DispatcherServlet
作为请求接收核心,再转到其它处理器处理的! webflux 基于 Socket, 使用的也不是 web 容器, 所以它的核心并不是servlet, webflux 使用org.springframework.web.reactive.DispatcherHandler
作为接收器, 以长连接的形式接收请求,作出相应, 以后有时间再详细看看webflux 源码
Gateway核心配置
配置文件 GatewayAutoConfiguration.java
这个配置bean 中的内容还是挺多的, 一个一个来吧!!!
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
@EnableConfigurationProperties
@AutoConfigureBefore({ HttpHandlerAutoConfiguration.class,
WebFluxAutoConfiguration.class })
@AutoConfigureAfter({ GatewayLoadBalancerClientAutoConfiguration.class,
GatewayClassPathWarningAutoConfiguration.class })
@ConditionalOnClass(DispatcherHandler.class)
public class GatewayAutoConfiguration {
...
//路由定位器构造器
@Bean
public RouteLocatorBuilder routeLocatorBuilder(
ConfigurableApplicationContext context) {
return new RouteLocatorBuilder(context);
}
...
}
看加类加载依赖, gateway 的自动配置加载顺序
HttpHandlerAutoConfiguration
和WebFluxAutoConfiguration
GatewayAutoConfiguration
GatewayLoadBalancerClientAutoConfiguration
和GatewayClassPathWarningAutoConfiguration
没别的感悟, 就是这个加载顺序…
路由构造器
gateway 匹配路由的方式有多种, 此处显示, gateway 以建造者模式, 配置不同的路由定位器
public class RouteLocatorBuilder {
...
/**
* Creates a new {@link Route}
* @param id the unique id for the route
* @param fn a function which takes in a {@link PredicateSpec} and returns a
* {@link Route.AsyncBuilder}
* @return a {@link Builder}
*/
public Builder route(String id, Function<PredicateSpec, Route.AsyncBuilder> fn) {
Route.AsyncBuilder routeBuilder = fn.apply(new RouteSpec(this).id(id));
add(routeBuilder);
return this;
}
/**
* Creates a new {@link Route}
* @param fn a function which takes in a {@link PredicateSpec} and returns a
* {@link Route.AsyncBuilder}
* @return a {@link Builder}
*/
public Builder route(Function<PredicateSpec, Route.AsyncBuilder> fn) {
Route.AsyncBuilder routeBuilder = fn.apply(new RouteSpec(this).randomId());
add(routeBuilder);
return this;
}
/**
* 创建一个路由定位器
*/
public RouteLocator build() {
return () -> Flux.fromIterable(this.routes)
.map(routeBuilder -> routeBuilder.build());
}
...
public static class RouteSpec {
private final Route.AsyncBuilder routeBuilder = Route.async();
private final Builder builder;
RouteSpec(Builder builder) {
this.builder = builder;
}
public PredicateSpec id(String id) {
this.routeBuilder.id(id);
return predicateBuilder();
}
public PredicateSpec randomId() {
return id(UUID.randomUUID().toString());
}
private PredicateSpec predicateBuilder() {
return new PredicateSpec(this.routeBuilder, this.builder);
}
}
}
创建构造器的方法, 这里注意, 一个带有 id, 一个不带有 id, 对应的是配置路由时的 id, id可以不配置, 会通过RouteSpec
随机生成 UUID 作为 路由id, 此时构造的构造器都是 AsyncBuilder extend AbstractBuilder
,
通过 RouteSpec
将 PredicateSpec extend UriSpec
放进 builder 中
初始化路由定位器与自定义路由定位器
public class 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, 将多有已经初始化过的RoutePredicateFactory
注入到集合中传入此初始化方法, 创建RouteDefinitionRouteLocator
, 进入构造函数
public class RouteDefinitionRouteLocator
implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {
...
private final Map<String, RoutePredicateFactory> predicates = new LinkedHashMap<>();
private final Map<String, GatewayFilterFactory> gatewayFilterFactories = new HashMap<>();
...
public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
List<RoutePredicateFactory> predicates,
List<GatewayFilterFactory> gatewayFilterFactories,
GatewayProperties gatewayProperties,
ConfigurationService configurationService) {
this.routeDefinitionLocator = routeDefinitionLocator;
this.configurationService = configurationService;
initFactories(predicates);
gatewayFilterFactories.forEach(
factory -> this.gatewayFilterFactories.put(factory.name(), factory));
this.gatewayProperties = gatewayProperties;
}
...
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 + "]");
}
});
}
...
}
看initFactories(predicates);
方法, 遍历所有 RoutePredicateFactory
, 定义对每一个factory 定义 key 放进predicates
这个 map中,进行缓存,factory.name()
这个名字作为 key, 这个是 LinkedHashMap是有顺序的由NameUtils.normalizeFilterFactoryName(getClass());
中实现如下
public static String normalizeRoutePredicateName(
Class<? extends RoutePredicateFactory> clazz) {
return removeGarbage(clazz.getSimpleName()
.replace(RoutePredicateFactory.class.getSimpleName(), ""));
}
名称规则为真实实例类名截掉RoutePredicateFactory所剩部分为 key 例如:
PathRoutePredicateFactory
类被初始化后的 key 为 Path
, 在启动 Gateway模块时,控制台会打印上面的日志
2019-05-20 20:24:09.325 INFO 3448 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [User]
2019-05-20 20:24:09.325 INFO 3448 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [After]
2019-05-20 20:24:09.325 INFO 3448 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Before]
2019-05-20 20:24:09.325 INFO 3448 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Between]
2019-05-20 20:24:09.326 INFO 3448 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Cookie]
2019-05-20 20:24:09.326 INFO 3448 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Header]
2019-05-20 20:24:09.326 INFO 3448 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Host]
2019-05-20 20:24:09.326 INFO 3448 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Method]
2019-05-20 20:24:09.326 INFO 3448 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Path]
2019-05-20 20:24:09.326 INFO 3448 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Query]
2019-05-20 20:24:09.326 INFO 3448 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [ReadBodyPredicateFactory]
2019-05-20 20:24:09.326 INFO 3448 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [RemoteAddr]
2019-05-20 20:24:09.326 INFO 3448 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Weight]
2019-05-20 20:24:09.326 INFO 3448 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [CloudFoundryRouteService]
这代表了所加载的所有 predicates, 配置的 gateway 路由匹配规则中, 就是路由规则类型
这个包下是 gateway 提供的所有 predicate, 在 GatewayAutoConfiguration
中都通过 Bean 进行了实例化, 通过上面的规则, 我们可以定义我们自己的请求匹配规则!
定义predicate
继承 AbstractRoutePredicateFactory
, 并定义内部类 Config
, 如下:
public class CustomerRoutePredicateFactory extends AbstractRoutePredicateFactory<CustomerRoutePredicateFactory.Config> {
public PathRoutePredicateFactory() {
super(Config.class);
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
//此处实现校验内容
return exchange -> {
exchange.getRequest()....
}
}
@Validated
public static class Config {
public Config setPatterns() {
//配置属性
}
}
}
进行初始化配置, 可以增加@component
注解或加@Bean
配置 等使其能注入到 RouteDefinitionRouteLocator
中
这个在配置文件中的配置类似于: - Customer=……
初始化路由过滤器与自定义路由过滤器
还是上面的源码
public class RouteDefinitionRouteLocator
implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {
...
private final Map<String, RoutePredicateFactory> predicates = new LinkedHashMap<>();
private final Map<String, GatewayFilterFactory> gatewayFilterFactories = new HashMap<>();
...
public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
List<RoutePredicateFactory> predicates,
List<GatewayFilterFactory> gatewayFilterFactories,
GatewayProperties gatewayProperties,
ConfigurationService configurationService) {
this.routeDefinitionLocator = routeDefinitionLocator;
this.configurationService = configurationService;
initFactories(predicates);
gatewayFilterFactories.forEach(
factory -> this.gatewayFilterFactories.put(factory.name(), factory));
this.gatewayProperties = gatewayProperties;
}
...
}
gatewayFilterFactories.forEach(
factory -> this.gatewayFilterFactories.put(factory.name(), factory));
这句代码遍历所有已初始化的过滤器, 然后放进gatewayFilterFactories
这个 map 属性中缓存, 规则同样是根据类实例的类名截掉根接口名, 不过这个接口是GatewayFilterFactory
public static String normalizeFilterFactoryName(
Class<? extends GatewayFilterFactory> clazz) {
return removeGarbage(clazz.getSimpleName()
.replace(GatewayFilterFactory.class.getSimpleName(), ""));
}
spring cloud 也提供了很多过滤器
自定义过滤器:
public class CustomerGatewayFilterFactory extends AbstractGatewayFilterFactory<CustomerGatewayFilterFactory.Config> {
@Override
public GatewayFilter apply(Config config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//内容实现
return null;
}
};
}
public class Config {
public Config() {
//参数接收实现
}
}
}
同样需要在初始化RouteLocator
前对这个类进行初始化@Component
或@bean
动态路由与自定义动态路由
public class GatewayAutoConfiguration {
...
//内存路由定义仓库
@Bean
@ConditionalOnMissingBean(RouteDefinitionRepository.class)
public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository() {
return new InMemoryRouteDefinitionRepository();
}
...
}
public class InMemoryRouteDefinitionRepository implements RouteDefinitionRepository {
private final Map<String, RouteDefinition> routes = synchronizedMap(
new LinkedHashMap<String, RouteDefinition>());
@Override
public Mono<Void> save(Mono<RouteDefinition> route) {
return route.flatMap(r -> {
if (StringUtils.isEmpty(r.getId())) {
return Mono.error(new IllegalArgumentException("id may not be empty"));
}
routes.put(r.getId(), r);
return Mono.empty();
});
}
@Override
public Mono<Void> delete(Mono<String> routeId) {
return routeId.flatMap(id -> {
if (routes.containsKey(id)) {
routes.remove(id);
return Mono.empty();
}
return Mono.defer(() -> Mono.error(
new NotFoundException("RouteDefinition not found: " + routeId)));
});
}
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
return Flux.fromIterable(routes.values());
}
}
在自动配置中配置了这么个实例: 他可以删除路由,添加路由, 获取所有路由, 这个类里还实现了一个LinkedHashMap<String, RouteDefinition>
的map缓存, 与类实例共生; 再向上找, 又有惊奇发现
public class AbstractGatewayControllerEndpoint implements ApplicationEventPublisherAware {
protected RouteDefinitionWriter routeDefinitionWriter;
/*
* http POST :8080/admin/gateway/routes/apiaddreqhead uri=http://httpbin.org:80
* predicates:='["Host=**.apiaddrequestheader.org", "Path=/headers"]'
* filters:='["AddRequestHeader=X-Request-ApiFoo, ApiBar"]'
*/
@PostMapping("/routes/{id}")
@SuppressWarnings("unchecked")
public Mono<ResponseEntity<Object>> save(@PathVariable String id,
@RequestBody RouteDefinition route) {
return Mono.just(route).filter(this::validateRouteDefinition)
.flatMap(routeDefinition -> this.routeDefinitionWriter
.save(Mono.just(routeDefinition).map(r -> {
r.setId(id);
log.debug("Saving route: " + route);
return r;
}))
.then(Mono.defer(() -> Mono.just(ResponseEntity
.created(URI.create("/routes/" + id)).build()))))
.switchIfEmpty(
Mono.defer(() -> Mono.just(ResponseEntity.badRequest().build())));
}
@DeleteMapping("/routes/{id}")
public Mono<ResponseEntity<Object>> delete(@PathVariable String id) {
return this.routeDefinitionWriter.delete(Mono.just(id))
.then(Mono.defer(() -> Mono.just(ResponseEntity.ok().build())))
.onErrorResume(t -> t instanceof NotFoundException,
t -> Mono.just(ResponseEntity.notFound().build()));
}
}
AbstractGatewayControllerEndpoint
提供 rest API
接口,向内存中添加, 删除路由配置, routeDefinitionWriter
是InMemoryRouteDefinitionRepository
的实例
再从自动配置开始看
public class CompositeRouteDefinitionLocator implements RouteDefinitionLocator {
private static final Log log = LogFactory
.getLog(CompositeRouteDefinitionLocator.class);
private final Flux<RouteDefinitionLocator> delegates;
private final IdGenerator idGenerator;
public CompositeRouteDefinitionLocator(Flux<RouteDefinitionLocator> delegates) {
this(delegates, new AlternativeJdkIdGenerator());
}
public CompositeRouteDefinitionLocator(Flux<RouteDefinitionLocator> delegates,
IdGenerator idGenerator) {
this.delegates = delegates;
this.idGenerator = idGenerator;
}
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
return this.delegates.flatMap(RouteDefinitionLocator::getRouteDefinitions)
.flatMap(routeDefinition -> Mono.justOrEmpty(routeDefinition.getId())
.defaultIfEmpty(idGenerator.generateId().toString())
.publishOn(Schedulers.elastic()).map(id -> {
if (routeDefinition.getId() == null) {
routeDefinition.setId(id);
if (log.isDebugEnabled()) {
log.debug("Id set on route definition: "
+ routeDefinition);
}
}
return routeDefinition;
}));
}
}
-
初始化RouteLocator时, 注入了 RouteDefinitionLocator
-
初始化RouteDefinitionLocator时, 已经注入了InMemoryRouteDefinitionRepository
-
RouteLocator可以通过RouteDefinitionLocator, 拿到InMemoryRouteDefinitionRepository里面的所有路由配置, 并且也是这么做的
public class RouteDefinitionRouteLocator implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware { ... @Override public Flux<Route> getRoutes() { return this.routeDefinitionLocator.getRouteDefinitions().map(this::convertToRoute) // TODO: error handling .map(route -> { if (logger.isDebugEnabled()) { logger.debug("RouteDefinition matched: " + route.getId()); } return route; }); /* * TODO: trace logging if (logger.isTraceEnabled()) { * logger.trace("RouteDefinition did not match: " + routeDefinition.getId()); } */ } ... }
返回值
Flux<Route>
是RouteDefinitionLocator
中所有RouteDefinitionLocator
的所有路由定义, 当然也包括InMemoryRouteDefinitionRepository
的
这个路径走通的话, 是不是就可以动态的向 gateway 中增加和删除路由了呢!!! 我觉得是的!!!
在AbstractGatewayControllerEndpoint
中的接口可以看到, 通过 json 传递RouteDefinition
对象就可以了, 然后就会通过this.routeDefinitionWriter
这个属性增加到内存中
那么这是 spring cloud 实现的, 内存方案的特点就是处理速度快, 但是重启后会丢失, 那么是不是重启后, 之前配的什么路由就不知道了, 还得重新找要配哪些, 是的, 就是这么 high!!!
-
设想, 增加数据库存储, 文件存储, nosql 存储, 是不是就能解决这个问题了
-
redis 自带RDB和 AOF备份, 再加上 mysql, 这样应该没问题
伪代码如下:
@Component public class InRedisRouteDefinitionRepository implements RouteDefinitionRepository { @Autowired private RedisTemplate redisTemplate; @Autowired private RouteDefinitionDao routeDefinitionDao; public InRedisRouteDefinitionRepository() { super(); Flux<RouteDefinition> dbRouteDefinitions = routeDefinitionDao.getAll(); Flux<RouteDefinition> rdRouteDefinitions = redisTemplate.getAll(); //获取差集 Flux<RouteDefinition> dsRouteDefinitions = differenceSet(dbRouteDefinitions, rdRouteDefinitions); //同步两库数据 routeDefinitionDao.same(); redisTemplate.same(); } @Override public Flux<RouteDefinition> getRouteDefinitions() { //从 redis 中获取所有路由配置 Flux<RouteDefinition> rdRouteDefinitions = redisTemplate.getAll(); return rdRouteDefinitions; } @Override public Mono<Void> save(Mono<RouteDefinition> route) { //向 redis 和 db 中增加路由配置 routeDefinitionDao.insert(route); redisTemplate.add(route); return Mono.empty(); } @Override public Mono<Void> delete(Mono<String> routeId) { //redis 和 db 中删除路由配置 routeDefinitionDao.delete(route); redisTemplate.del(route); return Mono.empty(); } }
InRedisRouteDefinitionRepository
增加自动注入配置, 会和InMemoryRouteDefinitionRepository`一样注入可以使用 webFlux接口, 支持 http 和 socket, 以流的方式或者 json 方式控制路由,
也可以使用触发器监听文件或其它行为, 只要能触发这些方法, 就可以, OK
初始化全局过滤器与自定义全局过滤器
public class GatewayAutoConfiguration {
//路由谓词处理映射(路径匹配)
@Bean
public RoutePredicateHandlerMapping routePredicateHandlerMapping(
FilteringWebHandler webHandler, RouteLocator routeLocator,
GlobalCorsProperties globalCorsProperties, Environment environment) {
return new RoutePredicateHandlerMapping(webHandler, routeLocator,
globalCorsProperties, environment);
}
//web 过滤处理器
@Bean
public FilteringWebHandler filteringWebHandler(List<GlobalFilter> globalFilters) {
return new FilteringWebHandler(globalFilters);
}
//路由谓词处理映射(路径匹配)
@Bean
public RoutePredicateHandlerMapping routePredicateHandlerMapping(
FilteringWebHandler webHandler, RouteLocator routeLocator,
GlobalCorsProperties globalCorsProperties, Environment environment) {
return new RoutePredicateHandlerMapping(webHandler, routeLocator,
globalCorsProperties, environment);
}
}
//过滤器处理器, 初始化注入所有全局过滤器放到globalFilters
public class FilteringWebHandler implements WebHandler {
private final List<GatewayFilter> globalFilters;
public FilteringWebHandler(List<GlobalFilter> globalFilters) {
this.globalFilters = loadFilters(globalFilters);
}
//通过适配器转化为 GatewayFilter, 进行操作
private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
return filters.stream().map(filter -> {
GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);
if (filter instanceof Ordered) {
int order = ((Ordered) filter).getOrder();
return new OrderedGatewayFilter(gatewayFilter, order);
}
return gatewayFilter;
}).collect(Collectors.toList());
}
//创建调用链, 根据实现的 Ordered排序
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
List<GatewayFilter> gatewayFilters = route.getFilters();
return new DefaultGatewayFilterChain(combined).filter(exchange);
}
//创建调用链, 根据实现的 Ordered排序
private static class DefaultGatewayFilterChain implements GatewayFilterChain {
private final List<GatewayFilter> filters;
@Override
public Mono<Void> filter(ServerWebExchange exchange) {
return Mono.defer(() -> {
if (this.index < filters.size()) {
GatewayFilter filter = filters.get(this.index);
DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this,
this.index + 1);
return filter.filter(exchange, chain);
}
else {
return Mono.empty(); // complete
}
});
}
}
private static class GatewayFilterAdapter implements GatewayFilter {
private final GlobalFilter delegate;
GatewayFilterAdapter(GlobalFilter delegate) {
this.delegate = delegate;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return this.delegate.filter(exchange, chain);
}
}
}
初始化过程:
- 自动注入, 加载所有实现
GlobalFilter
的过滤器, 注入到过滤器处FilteringWebHandler
理器中 - 通过过滤器处理器构造器初始化, 调用内部类适配器适配所有
GlobalFilter
为GatewayFilter
,并创建调用链, 调用链的顺序由过滤器实现的 Orderd接口排序 - 最后将
FilteringWebHandler
注入到RoutePredicateHandlerMapping
中, 每个请求, 都会通过这个处理器映射器, 然后由处理器映射器调用FilteringWebHandler
中的GlobalFilter
的 filter 方法 对 exchange 进行处理
设计模式: - 代理设计模式
- 适配器设计模式
自定义全局过滤器
实现GlobalFilter, Ordered, ApplicationListener<EnableBodyCachingEvent>
接口
实现onApplicationEvent
filter
getOrder
三个方法
@Override
public void onApplicationEvent(EnableBodyCachingEvent event) {
this.routesToCache.putIfAbsent(event.getRouteId(), true);
}
固定实现
filter 方法处理 exchange的 request 请求
getOrder返回整数, 表示调用链的调用顺序,
使用@Compnent 或@Bean 自动自动注入