一、执行过程:
客户端向 Spring Cloud Gateway 发出请求。然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑。
执行过程:
1).请求先由DispatcherHanlder进行处理,DispatcherHanlder初始化的时候会从IOC中查找实现HandlerMapping接口的实现类。然后保存到内部变量handlerMappings中,DispatcerHandler调用Handler方法迭代handler
Mappings中的HandlerMapping,
2).调用RoutePredicateHandlerMapping中的获取路由的方法,当RoutePredicateHandlerMapping获取到对应的路由的时候会将Route存储到ServerWebExchanges的属性中,然后返回实现了WebHandler接口的FilteringWebHandler。FilteringWebHandler是一个存放过滤器的Handler。这里的RouteLocator 是决定了路由规则从哪里加载。
3).最后DispatcherHanlder通过SimpleHandlerAdapter适配器的方式调用FilteringWebHandler的handler方法,FilteringWebHandler调用所有的过滤器,包括proxy filter。通过proxyFilter请求被代理的服务。处理完毕后,并将Response响应回去。
根据 Predicate、Uri匹配找到Route. 并保存在ServerWebExchange的AttributesMaps里。
从 RoutePredicateHandlerMapping完成后找到匹配的Route,进行过滤。
路由RouteLocator定位器:
1. RouteLocator:
RoutePredicateHandlerMapping里所用的到RouteLocator,是一个CachingRouteLocator Bean.实际上里由二个RouteLocator组成:RouteLocatorBuilder、RouteDefinitionRouteLocator组成的List<RouteLocator> routeLocators.
@Bean
@Primary
public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
}
2. RouteDefinitionLocator:
RouteDefinition定义加载器,主要来源是:PropertiesRouteDefinitionLocator(yml文件里定义的Route规则)和 所有RouteDefinitionLocator类的Bean.(开发者可自定义Route规则加载来源如从Redis)
另:使用Spring Bean容器,自动把相同类的实例Bean,作为List<Bean>参数注入。(Spring自动把相同类的Bean 归纳成一个List)
- Route(路由):路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由;
- Predicate(断言):指的是Java 8 的 Function Predicate。 输入类型是Spring框架中的ServerWebExchange。 这使开发人员可以匹配HTTP请求中的所有内容,例如请求头或请求参数。如果请求与断言相匹配,则进行路由;
- Filter(过滤器):指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前后对请求进行修改。
spring:
cloud:
gateway:
default-filters:
routes:
- id: i5xforyou-biz-auth
uri: lb://i5xforyou-biz-auth
predicates: ##1.请求通过predicates下的各条规则都匹配中了,就路由到uri里去
- Path= ${server.servlet.context-path}/auth/**
- Query= uid,12776
filters:
- StripPrefix= 1
```
default-filters: 里面可以定义一些共同的filter,对所有路由都起作用
routes:具体的路由信息,是一个数组,每一个路由基本包含部分:
id:这个路由的唯一id,不定义的话为一个uuid
uri:http请求为lb://前缀 + 服务id;ws请求为lb:ws://前缀 + 服务id;表示将请求负载到哪一个服务上
predicates:表示这个路由的请求匹配规则,只有符合这个规则的请求才会走这个路由。为一个数组,每个规则为并且的关系。
filters:请求转发前的filter,为一个数组。
order:这个路由的执行order
1. Predicate 断言:
Predicate 的特性实现了各种路由匹配规则,有通过 Header、请求参数等不同的条件来进行作为条件匹配到对应的路由。网上有一张图总结了 Spring Cloud 内置的几种 Predicate 的实现。
predicates:请求匹配规则,为一个数组,每个规则为并且的关系。包含:
1. name:规则名称,目前有10个,有Path,Query,Method,Header,After,Before,Between,Cookie,Host,RemoteAddr
2. args:参数key-value键值对,例如:
```
predicates:
- name: Query
args:
foo: ba
```
等价于
```
predicates:
- Query=foo, ba
```
2. Filter(过滤器)
过滤器可用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用。可分全局过滤器和专用过滤器。
二、源代码分析
1. 自动配置:
GatewayAutoConfiguration
2. RoutePredicate断言
@FunctionalInterface
public interface RoutePredicateFactory<C> extends ShortcutConfigurable, Configurable<C> {
String PATTERN_KEY = "pattern";
// useful for javadsl
default Predicate<ServerWebExchange> apply(Consumer<C> consumer) {
C config = newConfig();//生成配置信息
consumer.accept(config); //运行C config = newConfig() 里的各自的加载方法
beforeApply(config);
return apply(config);//进行匹配,由各个实现rotePredicate
}
default AsyncPredicate<ServerWebExchange> applyAsync(Consumer<C> consumer) {
C config = newConfig();
consumer.accept(config);
beforeApply(config);
return applyAsync(config);
}
default Class<C> getConfigClass() {
throw new UnsupportedOperationException("getConfigClass() not implemented");
}
@Override
default C newConfig() {
throw new UnsupportedOperationException("newConfig() not implemented");
}
default void beforeApply(C config) {}
Predicate<ServerWebExchange> apply(C config);
default AsyncPredicate<ServerWebExchange> applyAsync(C config) {
return toAsyncPredicate(apply(config));
}
default String name() {
return NameUtils.normalizeRoutePredicateName(getClass());
}
public class CookieRoutePredicateFactory extends AbstractRoutePredicateFactory<CookieRoutePredicateFactory.Config> {
public static final String NAME_KEY = "name";
public static final String REGEXP_KEY = "regexp";
public CookieRoutePredicateFactory() {
super(Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(NAME_KEY, REGEXP_KEY);
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return exchange -> {
//实现断言代码
List<HttpCookie> cookies = exchange.getRequest().getCookies().get(config.name);
if (cookies == null) {
return false;
}
for (HttpCookie cookie : cookies) {
if (cookie.getValue().matches(config.regexp)) {
return true;
}
}
return false;
};
}
@Validated
public static class Config {
@NotEmpty
private String name;
@NotEmpty
private String regexp;
public String getName() {
return name;
}
public Config setName(String name) {
this.name = name;
return this;
}
public String getRegexp() {
return regexp;
}
public Config setRegexp(String regexp) {
this.regexp = regexp;
return this;
}
}
}