Gateway的作用
Spring Cloud Gateway 组件的核心是通过一系列的过滤器,通过这些过滤器可以将客户端发送的请求转发(路由)到对应的微服务。
核心配置
- route:由id、uri、predicate、filters组成
- predicate:即断言,匹配路由的部件,支持正则表达式
- filters:过滤器,在断言匹配后执行,对路由信息进行操作,也可以操作header、参数等
方法一(配置文件)
1. 依赖
注意:由于gateway默认依赖webflux,所以不需要加入springboot-web的依赖,否则会报错;
同时,本次实验使用的是Zookeeper作为注册中心,所以不需要加入eureka-client的依赖,否则启动报错
<!--SpringCloud Gateway-->
<!--gateway依赖中包含了webflux,启动服务时会与spring-boot-web冲突,故不要添加web依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--SpringCloud Zookeeper-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<!--先排除zookeeper-discovery自带的zookeeper,防止冲突-->
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-config</artifactId>
</dependency>
2. yml
server:
port: 9527
spring:
profiles:
active:
application:
name: springcloud-gateway
cloud:
gateway:
routes:
- id: devilvan-route-strip
uri: lb://devilvan-caches/caches
predicates:
# 匹配满足条件的路由
- Path=/caches/cachesController/**
# Predicate断言后就会执行过滤器
filters:
# StripPrefix:将Path匹配的第1段路由(/caches)舍弃,真正的匹配路由为:/cachesController/**
- StripPrefix=1
- id: devilvan-route-prefix
uri: lb://devilvan-caches/caches
predicates:
- Path=/**
filters:
# PrefixPath:给匹配的Path的前面补充一个前缀,若输入路由:playCaffeineCaches
# 则真正的匹配路由为:/cachesController/playCaffeineCaches
- PrefixPath=/cachesController
zookeeper:
connect-string: localhost:2181
enabled: true
connection-timeout: 60000
3. 参数、细节
- routes可以设置多个,通过uri来区分不同的服务,也可由此来配置不同的predicates和filters
- predicates即断言,可配置的参数来自RoutePredicateFactory的实现类,例如:PathRoutePredicateFactory
- filters即过滤器,可配置的参数来自GatewayFilterFactory,例如:StripPrefixGatewayFilterFactory
- uri即经过断言和过滤器后,最终被转发到的IP+端口,也可以是一组服务
4. StripPrefix和PrefixPath
StripPrefix作用是:忽略当前路由的第n段路由,结合part使用
PrefixPath作用是:在当前路由的最前端加上一个自定义路由
5. 测试
原访问路由:localhost:8077/cachesController/playCaffeineCaches
添加如上配置的网关后的路由:
StripPrefix=1
http://localhost:9527/caches/cachesController/playCaffeineCaches => localhost:8077/cachesController/playCaffeineCaches
PrefixPath=/cacheController
http://localhost:9527/playCaffeineCaches == localhost:8077/cachesController/playCaffeineCaches
方法二(配置类)
此方法通过编码形式的配置类提供网关服务,效果和以上配置文件效果一样
核心部分为PredicateFactory和FilterFactory的运用,且都需要结合各自工厂的Config内部类使用,最终通过routes()方法连接起来
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("devilvan-route-strip", new Function<PredicateSpec, Route.AsyncBuilder>() {
@Override
public Route.AsyncBuilder apply(PredicateSpec predicateSpec) {
/*
* predicate
* 1. 创建匹配的断言对应的工厂,例如:yml配置中的path == PathRoutePredicateFactory
* 2. 通过工厂的newConfig产生对应的配置类对象,这个对象里可以set的属性就是可配置的参数
*/
PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory();
PathRoutePredicateFactory.Config pathRouteConfig = pathRoutePredicateFactory.newConfig();
List<String> pattern4StripPrefix = new ArrayList<>();
pattern4StripPrefix.add("/caches/cachesController/**");
pathRouteConfig.setPatterns(pattern4StripPrefix);
/*
* filters
* 1. filters在匹配断言后执行
* 2. 创建过滤器工厂,例如:yml配置中的StripPrefix == StripPrefixGatewayFilterFactory
* 3. 通过工厂的newConfig创建配置类,在配置类中给可配置参数赋值
* */
StripPrefixGatewayFilterFactory stripPrefixGatewayFilterFactory = new StripPrefixGatewayFilterFactory();
StripPrefixGatewayFilterFactory.Config stripConfig = stripPrefixGatewayFilterFactory.newConfig();
stripConfig.setParts(1);
stripPrefixGatewayFilterFactory.apply(stripConfig);
/*
* 组装predicate和filter
* 1. 即将predicate和filters连接起来
* 2. 通过PredicateSpec对象的predicate、filters等方法将断言和过滤器等联系起来
* 3. 内容基本都是:factory.apply(factory.config)
* */
predicateSpec.predicate(pathRoutePredicateFactory.apply(pathRouteConfig))
.filters(new Function<GatewayFilterSpec, UriSpec>() {
@Override
public UriSpec apply(GatewayFilterSpec gatewayFilterSpec) {
return gatewayFilterSpec.filter(stripPrefixGatewayFilterFactory.apply(stripConfig));
}
});
return predicateSpec.uri("lb://devilvan-caches/caches");
}
})
.route("devilvan-route-prefix", new Function<PredicateSpec, Route.AsyncBuilder>() {
@Override
public Route.AsyncBuilder apply(PredicateSpec predicateSpec) {
PathRoutePredicateFactory pathRoutePredicateFactory = new PathRoutePredicateFactory();
PathRoutePredicateFactory.Config pathRouteConfig = pathRoutePredicateFactory.newConfig();
List<String> pattern4PrefixPath = new ArrayList<>();
pattern4PrefixPath.add("/**");
pathRouteConfig.setPatterns(pattern4PrefixPath);
// filters
PrefixPathGatewayFilterFactory prefixPathGatewayFilterFactory = new PrefixPathGatewayFilterFactory();
PrefixPathGatewayFilterFactory.Config prefixPathConfig = prefixPathGatewayFilterFactory.newConfig();
prefixPathConfig.setPrefix("/cachesController");
// 组装predicate和filter
predicateSpec.predicate(pathRoutePredicateFactory.apply(pathRouteConfig))
.filters(new Function<GatewayFilterSpec, UriSpec>() {
@Override
public UriSpec apply(GatewayFilterSpec gatewayFilterSpec) {
return gatewayFilterSpec.filter(prefixPathGatewayFilterFactory.apply(prefixPathConfig));
}
});
return predicateSpec.uri("lb://devilvan-caches/caches");
}
})
.build();
}
}