【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(七)Spring Cloud Gateway服务网关

本文涉及的产品
网络型负载均衡 NLB,每月750个小时 15LCU
传统型负载均衡 CLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
简介: 【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(七)Spring Cloud Gateway服务网关

1、GateWay概述

zuul停更了

gateway之所以性能号,因为底层使用WebFlux,而webFlux底层使用netty通信(NIO)

SpringCloud Gateway使用的是Webflux中的reactor-netty响应式编程组件,底层使用了Netty通讯框架

2、GateWay的特性:

Gateway能干什么?

  • 反向代理
  • 鉴权
  • 流量控制
  • 熔断
  • 日志监控

3、GateWay与zuul的区别:

4、zuul1.x的模型:

5、什么是webflux:

是一个非阻塞的web框架,类似springmvc这样的

6、GateWay三大概念:

6.1,路由:

路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如断言为true则匹配该路由

就是根据某些规则,将请求发送到指定服务上

6.2,断言:

参考的是Java8的java.util.function.Predicate 开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由

就是判断,如果符合条件就是xxxx,反之yyyy

6.3,过滤:

指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改.

路由前后,过滤请求

7、GateWay的工作原理:

Gateway的核心逻辑:路由转发+执行过滤器

下章开始配置一个gateway网关。

8、使用GateWay:

8.1,建module

新建一个GateWay的模块项目

名字: Cloud-gateway-9527

8.2,修改pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud2023</artifactId>
        <groupId>com.tigerhhzz.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>Cloud-gateway-9527</artifactId>
    <dependencies>
        <!--gateway-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--Springboot web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--Springboot actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--eureka-client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.tigerhhzz.springcloud-tigerhhzz</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- 引入lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- 引入srpingboot test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
8.3,写配置文件
server:
  port: 9527
spring:
  application:
    name: cloud-gateway-service
eureka:
  instance:
    hostname: cloud_gateway_service
  client:
    service-url:
      defaultZone: http://www.eureka7001.com:7001/eureka/
    register-with-eureka: true
    fetch-registry: true
8.4,主启动类
package com.tigerhhzz.springcloud;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
@Slf4j
public class GateWayMain9527 {
    public static void main(String[] args) {
        SpringApplication.run(GateWayMain9527.class,args);
        log.info("GateWayMain9527启动成功~~~~~~~~~~~~~~~~~~~");
    }
}
8.5,针对pay模块,设置路由:

我们目前不想暴露8001端口,希望在8001外面套一层9527

cloud-provider-payment8001看看controller的访问地址(两个controller 分别是如下)

@GetMapping("/payment/lb")
    public String getPaymentLB(){
        return serverPort;
    }
  @GetMapping(value = "/payment/{id}")
  public CommonResult getPaymentById(@PathVariable("id")Long id){
      Payment result = paymentService.getPaymentById(id);
      log.info("****查询结果:" + result);
      if(result != null){
          return new CommonResult(200, "查询成功,serverPort:  "+serverPort, result);
      }
      return new CommonResult(400, "没有对应id的记录", null);

**修改GateWay模块(9527)的配置文件:

server:
  port: 9527
spring:
  application:
    name: cloud-gateway-service
  cloud:
    gateway:
      routes: #多个路由
        - id: payment_routh                       #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001   #匹配后提供服务的路由地址
          #uri: lb://cloud-payment-service         #路由的ID,没有固定规则但要求唯一,建议配合服务名
          predicates: #断言
            - Path=/payment/**                #断言 路径相匹配的进行路由
        - id: payment_routh2
          uri: http://localhost:8001
          #uri: lb://cloud-payment-service
          predicates:
            - Path=/payment/lb/**
            #- After=2022-06-16T19:49:30.417+08:00[Asia/Shanghai]
            #- Cookie=username,tigerhhzz
eureka:
  instance:
    hostname: cloud_gateway_service
  client:
    service-url: //服务提供者provider注册进eureka服务中心
      defaultZone: http://www.eureka7001.com:7001/eureka/
    register-with-eureka: true
    fetch-registry: true

这里表示,

当访问localhost:9527/payment/31时,

路由到localhost:8001/payment/31

8.6,开始测试

启动Cloud-eureka-server7001

启动Cloud-provider-payment8001

启动Cloud-gateway-9527

如果启动GateWay报错
        可能是GateWay模块引入了web和监控的starter依赖,需要移除

访问:

添加网关前:http://localhost:8001/payment/1

添加网关后:http://localhost:9527/payment/1

9、GateWay的网关配置,

Gateway网关路由有两种配置方式:

  • 在配置文件yaml中配置
  • 代码中注入RouteLocator的Bean

GateWay的网关配置,除了支持配置文件,还支持硬编码方式

9.1 使用硬编码配置GateWay:

自己写一个:通过9527网关访问到外网的百度和腾讯网站

创建配置类:

package com.tigerhhzz.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
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        RouteLocatorBuilder.Builder routes = builder.routes();
        routes.route("path_route",r->r.path("/baidunews").uri("https://news.baidu.com/"));
        return routes.build();
    }
    @Bean
    public RouteLocator customRouteLocator2(RouteLocatorBuilder builder) {
        RouteLocatorBuilder.Builder routes = builder.routes();
        routes.route("path_route1",r->r.path("/tencent").uri("https://www.tencent.com/"));
        return routes.build();
    }
}
9.2 重启服务 测试
9.3 通过服务名实现动态路由

上面的配置虽然首先了网关,但是是在配置文件中写死了要路由的地址

现在需要修改,不指定地址,而是根据微服务名字进行路由,我们可以在注册中心获取某组微服务的地址

默认情况下Gatway会根据注册中心注册的服务列表, 以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能

需要注意的是uri的协议lb,表示启用Gateway的负载均衡功能.

lb://serverName是spring cloud gatway在微服务中自动为我们创建的负载均衡uri

需要:

一个eureka7001+两个服务提供者8001/8002

9.3.1 修改GateWay模块的配置文件:
server:
  port: 9527
spring:
  application:
    name: cloud-gateway-service
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes: #多个路由
        - id: payment_routh                       #路由的ID,没有固定规则但要求唯一,建议配合服务名
          #uri: http://localhost:8001   #匹配后提供服务的路由地址
          uri: lb://cloud-provider-service         #路由的ID,没有固定规则但要求唯一,建议配合服务名
          predicates: #断言
            - Path=/payment/**                #断言 路径相匹配的进行路由
        - id: payment_routh2
          #uri: http://localhost:8001
          uri: lb://cloud-provider-service
          predicates:
            - Path=/payment/lb/**
            #- After=2022-06-16T19:49:30.417+08:00[Asia/Shanghai]
            #- Cookie=username,tigerhhzz
eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url: #服务提供者provider注册进eureka服务中心
      defaultZone: http://localhost:7001/eureka/
    register-with-eureka: true
    fetch-registry: true
9.3.2 然后就可以启动微服务.测试

8001/8002两个端口切换 http://localhost:9527/payment/lb

9.3.3 Pridicate断言:

我们之前在配置文件中配置了断言:

这个断言表示,如果外部访问路径是指定路径,就路由到指定微服务上

可以看到,这里有一个Path,这个是断言的一种,断言的类型:

After:
        可以指定,只有在指定时间后,才可以路由到指定微服务
• 1
• 2

这里表示,只有在2020年的2月21的15点51分37秒之后,访问才可以路由

在此之前的访问,都会报404

如何获取当前时区?**

import java.time.ZonedDateTime;
/**
 * @author tigerhhzz
 * @date 2023/4/17 17:10
 */
public class T2 {
    public static void main(String[] args) {
        ZonedDateTime now = ZonedDateTime.now();
        System.out.println(now);
        //2023-04-17T17:11:53.743+08:00[Asia/Shanghai]
    }
}
before:
        与after类似,他说在指定时间之前的才可以访问
        between:
        需要指定两个时间,在他们之间的时间才可以访问

cookie:
        只有包含某些指定cookie(key,value),的请求才可以路由

利用curl访问测试:

yml中加上:

- Cookie=username,tigerhhzz

curl测试:

Header:
        只有包含指定请求头的请求,才可以路由

测试:

host:
        只有指定主机的才可以访问,
        比如我们当前的网站的域名是www.aa.com
        那么这里就可以设置,只有用户是www.aa.com的请求,才进行路由

可以看到,如果带了域名访问,就可以,但是直接访问ip地址.就报错了

method:
        只有指定请求才可以路由,比如get请求...

path:
        只有访问指定路径,才进行路由
        比如访问,/abc才路由

Query:
        必须带有请求参数才可以访问

9.3.4 Filter过滤器:

生命周期:

在请求进入路由之前,和处理请求完成,再次到达路由之前

种类:

GateWayFilter,单一的过滤器

与断言类似,比如闲置,请求头,只有特定的请求头才放行,反之就过滤:

GlobalFilter,全局过滤器:

自定义过滤器:

实现两个接口

package com.tigerhhzz.springcloud.filter;
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 MyGateWayFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("**************come in MylogGateWayGilter:  " + new Date());
        String uname = exchange.getRequest().getQueryParams().getFirst("uname");
        if (uname == null) {
            System.out.println("********用户名为空,非法用户。");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }
    @Override
    public int getOrder() {
        return 0;
    }
}

然后启动服务,即可,因为过滤器通过@COmponet已经加入到容器了

相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
目录
相关文章
|
3月前
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
208 6
|
3月前
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
79 1
|
2月前
|
Java 开发者 微服务
从单体到微服务:如何借助 Spring Cloud 实现架构转型
**Spring Cloud** 是一套基于 Spring 框架的**微服务架构解决方案**,它提供了一系列的工具和组件,帮助开发者快速构建分布式系统,尤其是微服务架构。
271 69
从单体到微服务:如何借助 Spring Cloud 实现架构转型
|
2月前
|
运维 监控 持续交付
微服务架构解析:跨越传统架构的技术革命
微服务架构(Microservices Architecture)是一种软件架构风格,它将一个大型的单体应用拆分为多个小而独立的服务,每个服务都可以独立开发、部署和扩展。
486 36
微服务架构解析:跨越传统架构的技术革命
|
23天前
|
人工智能 安全 Java
微服务引擎 MSE:打造通用的企业级微服务架构
微服务引擎MSE致力于打造通用的企业级微服务架构,涵盖四大核心内容:微服务技术趋势与挑战、MSE应对方案、拥抱开源及最佳实践。MSE通过流量入口、内部流量管理、服务治理等模块,提供高可用、跨语言支持和性能优化。此外,MSE坚持开放,推动云原生与AI融合,助力企业实现无缝迁移和高效运维。
|
2月前
|
存储 SpringCloudAlibaba Java
【SpringCloud Alibaba系列】一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论
一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论。
【SpringCloud Alibaba系列】一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论
|
3月前
|
消息中间件 供应链 架构师
微服务如何实现低耦合高内聚?架构师都在用的技巧!
本文介绍了微服务的拆分方法,重点讲解了“高内聚”和“低耦合”两个核心设计原则。高内聚强调每个微服务应专注于单一职责,减少代码修改范围,提高系统稳定性。低耦合则通过接口和消息队列实现服务间的解耦,确保各服务独立运作,提升系统的灵活性和可维护性。通过领域建模和事件通知机制,可以有效实现微服务的高效拆分和管理。
81 7
|
3月前
|
JavaScript Java API
深入解析微服务的架构设计与实践
深入解析微服务的架构设计与实践
53 0
|
4月前
|
Kubernetes 安全 微服务
使用 Istio 缓解电信 5G IoT 微服务 Pod 架构的安全挑战
使用 Istio 缓解电信 5G IoT 微服务 Pod 架构的安全挑战
84 8
|
4月前
|
消息中间件 负载均衡 Cloud Native
云原生之旅:从容器到微服务的架构演变
在数字化转型的风潮中,云原生技术以其灵活性、可扩展性和弹性而备受青睐。本文将通过一个虚拟的故事,讲述一个企业如何逐步拥抱云原生,实现从传统架构向容器化和微服务架构的转变,以及这一过程中遇到的挑战和解决方案。我们将以浅显易懂的方式,探讨云原生的核心概念,并通过实际代码示例,展示如何在云平台上部署和管理微服务。