netflix公司研发出了zuul。
zuul现在已经停止更新,之前要出zuul2,zuul2的研发也一直延迟。
zuul一直做网关的效果。
Gateway是SpringCloud公司自研发的第二代微服务网关,代替了zuul。
Gateway的位置:

SpringCloud Gateway网关底层用了netty通讯框架:

webflux是什么?
项目架构图:

网关gateway的三个核心概念:
Gateway网关架构图:
路由转发 + 执行过滤器链。
官方架构图:

第一步:创建项目,配置依赖。
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-gatewayartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
第二步:修改application.yml文件,添加路由ID,路由地址,断言。
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_routh # 路由ID。 没有固定规则但要求唯一,建议配合服务名。
uri: http://localhost:8001 # 路由地址。 匹配后提供服务的路由地址。
predicates:
- Path=/payment/get/** # 断言。 路径相匹配的进行路由。
- id: payment_routh2 # 路由ID。 没有固定规则但要求唯一,建议配合服务名。
uri: http://localhost:8001 # 路由地址。 匹配后提供服务的路由地址。
predicates:
- Path=/payment/lb/** # 断言。 路径相匹配的进行路由。
eureka:
instance:
hostname: cloud-gateway-service
client:
service-url:
# 表示是否将自己注册进EurekaServer默认为true
register-with-eureka: true
# 是否从eurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetch-registry: true
# 入驻地址是哪个
defaultZone: http://eureka7001.com:7001/eureka # 单机
注意事项:
第三步:启动项目,进行测试。

第一种:就是上面演示的,在配置文件yml里面配置。
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_routh # 路由ID。 没有固定规则但要求唯一,建议配合服务名。
uri: http://localhost:8001 # 路由地址。 匹配后提供服务的路由地址。
predicates:
- Path=/payment/get/** # 断言。 路径相匹配的进行路由。
- id: payment_routh2 # 路由ID。 没有固定规则但要求唯一,建议配合服务名。
uri: http://localhost:8001 # 路由地址。 匹配后提供服务的路由地址。
predicates:
- Path=/payment/lb/** # 断言。 路径相匹配的进行路由。
第二种:代码注入routeLocator的bean。
package com.itholmes.springcloud.config;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class GateWayConfig {
//使用注入bean的方式来修改网关的路由
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
// 这里映射百度的地址 , 目录为https://news.baidu.com/guonei
//这样访问http://localhost:9527/guonei 就会 访问到 https://news.baidu.com/guonei的信息
routes.route("path_route_itholmes",
r -> r.path("/guonei")
.uri("https://news.baidu.com/guonei"));
return routes.build();
}
}
以上我们配置的路由都是写死的,默认情况下Gateway会根据注册中心注册的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能。
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
# 开启从注册中心动态创建路由的功能,利用微服务名进行路由。
enabled: true
routes:
- id: payment_routh # 路由ID。 没有固定规则但要求唯一,建议配合服务名。
# uri: http://localhost:8001 # 路由地址。 匹配后提供服务的路由地址。
uri: lb://CLOUD-PAYMENT-SERVICE
predicates:
- Path=/payment/get/** # 断言。 路径相匹配的进行路由。
- id: payment_routh2 # 路由ID。 没有固定规则但要求唯一,建议配合服务名。
# uri: http://localhost:8001 # 路由地址。 匹配后提供服务的路由地址。
uri: lb://CLOUD-PAYMENT-SERVICE
predicates:
- Path=/payment/lb/** # 断言。 路径相匹配的进行路由。
eureka:
instance:
hostname: cloud-gateway-service
client:
service-url:
# 表示是否将自己注册进EurekaServer默认为true
register-with-eureka: true
# 是否从eurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetch-registry: true
# 入驻地址是哪个
defaultZone: http://eureka7001.com:7001/eureka # 单机
Predicate断言有多种,就像加了where条件一样,来判断该路由是否符合条件:

对于三个时间范围的route predicate,时间范围内符合的路由请求:
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
# 开启从注册中心动态创建路由的功能,利用微服务名进行路由。
enabled: true
routes:
- id: payment_routh2 # 路由ID。 没有固定规则但要求唯一,建议配合服务名。
# uri: http://localhost:8001 # 路由地址。 匹配后提供服务的路由地址。
uri: lb://CLOUD-PAYMENT-SERVICE
predicates:
- Path=/payment/lb/** # 断言。 路径相匹配的进行路由。
- After=2022-07-01T09:42:44.070+08:00[Asia/Shanghai] # 在这个时间之后的请求,才能正常通过路由。
- before=2022-07-01T09:42:44.070+08:00[Asia/Shanghai] # 在这个时间之前的请求,才能正常通过路由。
- Between=2022-07-01T09:42:44.070+08:00[Asia/Shanghai],2022-07-01T09:42:44.070+08:00[Asia/Shanghai] # 在这个时间之间,才能正常通过路由。
Cookie Route Predicate参数:
predicates:
- Path=/payment/lb/** # 断言。 路径相匹配的进行路由。
- Cookie=username,zzyy # cookie,key是username,value是zzyy

通过curl可以测试有cookie请求和没有cookie请求的效果:

Header Route Predicate参数:

同上:




Query Route Predicate:

这里指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。
Spring Cloud Gateway的filter的生命周期:
Spring Cloud Gateway的filter的种类:
对于GatewayFilter 和 GlobalFilter的过滤器有很多种不同的类型。
自定义全局GatewayFilter过滤器:
package com.itholmes.springcloud.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Date;
@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("*******come in MyLogGateWayFilter: "+new Date());
//exchange.getRequest()
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if (uname == null){
log.info("*********用户名为null,非法用户!");
//exchange.getResponse() , HttpStatus.NOT_ACCEPTABLE是不可用请求。
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
Mono<Void> voidMono = exchange.getResponse().setComplete();
return voidMono;
}
//放行,去下一个过滤链
return chain.filter(exchange);
}
@Override
public int getOrder() {
//order就是顺序,一般是数字越小,优先级越高。
return 0;
}
}

多个微服务之间都需要进行必要的配置信息才能运行,所以要有一套集中式的,动态的配置管理设施是必不可少的(意思就是可以统一的配置application.yml)。
官方解释:

SpringCloud Config 分为 服务端 和 客户端两部分。

Spring cloud config的几个作用:

SpringCloud Config默认使用Git来存储配置文件(也有其他方式SVN,本地文件),推荐还是使用Git。
也就是搭建下面服务器:

第一步:在Github上新建一个名为springcloud-config的新Repository仓库。获取git地址。并且将仓库clone克隆下来。

第二步:创建项目,添加依赖。
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-config-serverartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
第三步:修改application.yml文件。
server:
port: 3344
spring:
application:
name: cloud-config-center # 微服务名称
cloud:
config:
server:
git:
uri: https://gitee.com/lixiaogou/sprincloud-config.git #GitHub上面的git仓库名字
search-paths: #搜索目录
- springcloud-config
label: master #读取分支
# 服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
第四步:添加启动类,添加@EnableConfigServer //开启config服务。
package com.itholmes.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer //开启config服务
public class ConfigCenterMain3344 {
public static void main(String[] args) {
SpringApplication.run(ConfigCenterMain3344.class,args);
}
}
对应公式如下:

官方公式:

SpringCloud Config有客户端和服务端。
第一步:创建项目,添加SpringCloud Config客户端依赖。
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-configartifactId>
dependency>
第二步:创建bootstrap.yml配置文件。

server:
port: 3355
spring:
application:
name: config-client
cloud:
# SpringCloud Config 客户端配置
config:
label: master # 分支名称
name: config # 配置文件名称
profile: dev # 读取后缀名称
# 上述三个综合: master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
uri: http://localhost:3344 # 配置中心地址
# 服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka

第三步:测试接口,http://localhost:3355/configInfo。
package com.itholmes.springcloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConfigClientController {
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo(){
return configInfo;
}
}
最大的问题就是分布式配置的动态刷新问题:
第一步:添加actuator监控依赖。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
第二步:暴露监控端点。
server:
port: 3355
spring:
application:
name: config-client
cloud:
# SpringCloud Config 客户端配置
config:
label: master # 分支名称
name: config # 配置文件名称
profile: dev # 读取后缀名称
# 上述三个综合: master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
uri: http://localhost:3344 # 配置中心地址
# 服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"
第三步:controller层添加@RefreshScope注解。
package com.itholmes.springcloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RefreshScope
public class ConfigClientController {
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo(){
return configInfo;
}
}
注意:配置上以上内容,并不能动态刷新,还必须由运维人员发送Post请求刷新3355才行!
第四步:由运维人员发送Post请求刷新3355。
这样的配置是优缺点: