概述简介
官网:
zuul 1.X : https://github.com/Netflix/zuul/wiki
Gateway: http://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html
是什么
cloud全家桶中有个很重要的组件就是网关,在1.X版本中都采用了zuul网关;
但在2.x版本中,zuul的升级一直在跳票,SpringCloud最后自己研发了一个网关代替zuul. gateway是原zuul1.x版的替代.
Gateway是在Spring生态系统之上构建的API网关服务,基于Spring5,SpringBoot 2 和Project Reactor等技术.
Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能,例如: 熔断,限流,重试等.
Spring Cloud Gateway作为Spring Cloud生态系统中的网关,目标是代替zuul.在Spring Cloud 2.0以上版本中,没有对新版本的zuul2.0以上最新高性能版本进行集成,仍然还是使用了zuul 1.x非Reactor模式的老版本,而为了提供网关的性能,Spring Cloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty.
SpringCloud Gateway 使用的webFlux中的reactor-netty响应式编程组件,底层使用了Netty通讯框架.
能干嘛
反向代理:
鉴权;
流量控制
熔断
日志监控
…
微服务架构中网关在哪里
有zuul了怎么又出来了Gateway
Zuul 1.0 已经进入了维护阶段,而且Gateway是SpringCloud团队研发的,而且很多功能Zuul都没有用起来也非常的简单便捷.
Gateway是基于异步非阻塞模型上进行开发的,性能方面不要担心,虽然Netfix早就发不了最新的Zuul 2.x,但是Spring Cloud没有整合,而且Netflix相关组件都宣布进入维护期;不知前景如何?
Spring Cloud Gateway具有如下特性:
基于Spring Framework 5,Project Reactor 和 Spring Boot2.0进行构建;
动态路由: 能够匹配任何请求属性;
可以对路由指定Predicate(断言) 和 Filter(过滤器);
集成Hystrix的断路器功能;
集成Spring Cloud服务发现功能;
易于编写Predicate(断言) 和 Fiter(过滤器);
请求限流功能;
支持路径重写.
Spring Cloud Gateway 与Zuul的区别:
在Spring Cloud Finchley 正式版之前,Spring Cloud推荐的网关是Netflix 提供Zuul:
- Zuul 1.x 是基于阻塞 I/O 的API Gateway
- Zuul1.x 基于Servlet 2.5使用阻塞架构,它不支持任何长连接(如 WebSocket) Zuul 的涉及模式和Nginx较像,每次 I/O 操作都是从工作线程中选择一个执行,请求线程被阻塞到工作线程完成,但是差别是Nginx用C++实现,Zuul用java实现,而JVM本身会有第一次加载比较慢的情况,是的Zuul的性能相对交差.
- Zuul 2.x理念更加先进,想基于Netty非阻塞和支持长连接,但SpringCloud目前还没有整合.Zuul 2.x的性能较Zuul 1.x有较大提升,在性能方面,根据官方提供的基准测试,Spring Cloud Gateway的RPS(每秒请求数)是Zuul的1.6倍.
- SpringCloud Gateway 建立在Spring Framework 5, Project Reactor 和 Spring boot 2 之上,使用非阻塞API.
- Spring Cloud Gateway 还支持webSocket,并且Spring 紧密集成拥有更好的开发体验.
Zuul 1.0模型 和 Gateway模型区别?
Spring cloud 中所集成的Zuu版本,采用的是Tomcat容器,使用的是传统的Servlet IO处理模型.
Servlet的生命周期?servlet由servlet container进行生命周期管理.
container启动时构造servlet对象并调用servlet init() 进行初始化;
container运行时接受请求,并为每个请求分配一个线程(一般从线程池中获取空闲线程) 然后调用service().
container关闭时调用servlet destory()销毁servlet;
传统定的web框架,比如说: strut2,springMVC等都是基于Servlet API与Servlet容器基础之上运行的.
但是
在servlet 3.1之后有了异步非阻塞的支持.而WebFlux是一个典型非阻塞异步的框架,它的核心是基于Reactor的相关API实现的.相对于在传统的web框架来说,它可以运行在诸如Netty,Undertow及支持Servlet3.1的容器上.非阻塞式+ 函数式编程(Spring5必须让你使用java8) Spring WebFlux是Spring 5.0引入的新的响应式框架,区别于SpringMVC,它不需要依赖Servlet API.它是完全异步非阻塞的,并且基于Reactor来实现响应式流规范.
三大核心概念
Route(路由): 路由是构建网关的基本模块,它由ID,目标URL,一系列的断言和过滤器组成,如果断言为true则匹配该路由.
Predicate(断言)
参考的是JAVA8D的java,util.function.Predicatte
开发人员可以匹配Http请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由
Filter(过滤)
指的是Spring框架中GatewayFiler的实例,使用过滤器,可以在请求被路由前或之后对请求进行修改.
Gateway工作流程
入门配置
- 建立网关工程
cloud-Gateway-Gateway9527 - pom.xml
<dependencies>
<!--引入自己的公共api-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-web</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-actuator</artifactId>-->
<!-- </dependency>-->
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
- yml
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
uri: http://localhost:8001
predicates:
- Path=/payment/lb/**
eureka:
instance:
hostname: cloud-gateway-service
client:
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka
- 主启动类
@SpringBootApplication
@EnableEurekaClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class,args);
}
}
- 业务类, 省略…
Gateway 不涉及业务, 后续写过滤器 - 启动测试
先测试:正常服务是否启动正常
http://localhost:8001/payment/get/1
网关测试:
http://localhost:9527/payment/get/1
2.用代码方式配置:
案例,访问百度新闻地址:http://news.baidu.com/guonei
a. 在业务类写配置baen的方法:
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 {
/*
* 配置了一个id 为routes_01的路由规则
* 当访问地址http://localhost:9527/guonei时会自行转发到地址: http://news.baidu.com/guonei
*/
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
routes.route("routes_01",
r -> r.path("/guonei") // 访问网关的guonei,将会路由到uri指定的地址
.uri("http://news.baidu.com/guonei")).build(); // http://news.baidu.com/guonei
return routes.build();
}
b. 测试:
测试地址:http://localhost:9527/guonei
通过微服务名实现动态路由
上述配置的是单机版模式,如果服务提供方式集群方式的话,我们需要在yml文件上配置动态路由的访问方式.
a. 加依赖,所有的微服务都需要加gateway 依赖.
b. 配置yml
b.1 开启从注册中心动态创建路由的功能,利用微服务名进行路由
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
b.2 匹配后提供服务名的路由地址
routes:
- id: payment_routh # 路由的ID,没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 # 匹配后, 提供服务的路由指引地址
uri: lb://cloud-payment-service
predicates:
- Path=/payment/get/** # 断言, 路径相匹配的进行路由
- id: payment_routh2
# uri: http://localhost:8001
uri: lb://cloud-payment-service # 匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/**
c. 整体的效果如下:
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_routh # 路由的ID,没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 # 匹配后, 提供服务的路由指引地址
uri: lb://cloud-payment-service
predicates:
- Path=/payment/get/** # 断言, 路径相匹配的进行路由
- id: payment_routh2
# uri: http://localhost:8001
uri: lb://cloud-payment-service # 匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/**
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
eureka:
instance:
hostname: cloud-gateway-service
client:
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka
e. 测试
测试http://localhost:9527/payment/get/1
返回的端口不一致
Predicate的使用
Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapping基础框架的一部分.
Spring Cloud Gateway 包括许多内置的Route Predicate工厂,所有这些Predicate 都与Http请求的不同属性匹配,多个Route Predicate工厂可以进行组合.
官网:
Filter的使用
Filter:指的是Spring 框架GatewayFilter的实例,使用过滤器,可以在请求被路由前或之后对请求进行修改.
路由过滤器可用于修改进入的Http请求和返回的Http响应,路由过滤器只能指定路由进行使用.
Spring Cloud Gateway内置了多种路由过滤器,他们都由GatewayFilter的工厂类来产生.
Filter的生命周期:
Only Two
pre 业务逻辑之前
post 业务逻辑之后
种类:
Only Two
GatewayFilter 单一的 官网31种之多
GlobalFilter 全局的
自定义过滤器
需要实现两个接口: implements GlobalFilter,Ordered
作用:全局日志记录
统一网关鉴权
自定义过滤器器
在业务类写一个拦截器
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
public class MyLogGateWayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("**************" +new Date());
String key = exchange.getRequest().getQueryParams().getFirst("key");
if (key == null){
System.out.println("*****用户名为空: "+key+"*******"); // 如果key值为空
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE); // 进行拦截
return exchange.getResponse().setComplete();
}
return chain.filter(exchange); // 如果key不为空 放行.
}
@Override
public int getOrder() { // 加载执行顺序
return 0; // 数值越小,越先执行.
}
}