微服务架构➖SpringCloud➖Gateway(1)

微服务架构➖SpringCloud➖Gateway

关于作者

  • 作者介绍

🍓 博客主页:作者主页

🍓 简介:JAVA领域优质创作者🥇、一名在校大三学生🎓、在校期间参加各种省赛、国赛,斩获一系列荣誉 🏆、阿里云专家博主51CTO专家博主

🍓 关注我:关注我学习资料、文档下载统统都有,每日定时更新文章,励志做一名JAVA资深程序猿👨‍💻


1. 什么是网关

网关是微服务最边缘的服务,直接暴露给用户,用来做用户和微服务的桥梁。

  • 没有网关:客户端直接访问我们的微服务,会需要在客户端配置很多的 ip:port,如果 user-service 并发比较大,则无法完成负载均衡
  • 有网关:客户端访问网关,网关来访问微服务,(网关可以和注册中心整合,通过服务名称找到目标的 ip:prot)这样只需要使用服务名称即可访问微服务,可以实现负载均衡,可 以实现 token 拦截,权限验证,限流等操

2. 简介

你们项目里面 用的什么网关? gateway zuul,它是 Spring Cloud 官方提供的用来取代 zuul(netflix)的新一代网关。(zuul:1.0 , 2.0 ,zuul 的本质,一组过滤器,根据自定义的过滤器顺序来执行,本质就是 web 组件 web 三大组件(监听器 过滤器

Zuul1.0 使用的是 BIO(Blocking IO) tomcat7.0 以前都是 BIO 性能一般

Zuul2.0 性能好 NIO AIO 异步非阻塞 io a+nio = aio = async + no blocking io,它基于 spring5.x,springboot2.x 和 ProjectReactor 等技术。 它的目地是让路由更加简单,灵活,还提供了一些强大的过滤器功能,例如:熔断、限流、重 试,自义定过滤器等 token 校验 ip 黑名单等

SpringCloud Gateway作为Spring Cloud生态的网关,目标是替代Zuul,在SpringCloud2.0 以上的版本中,没有对新版本的 zuul2.0 以上的最新高性能版本进行集成,仍然还是使用的 zuul1.x[可以看项目依赖找到]非 Reactor 模式的老版本。而为了提升网关的性能,SpringCloud Gateway 是基于 webFlux 框架实现的,而 webFlux 框架底层则使用了高性能 的 Reactor 模式通信框架的 Netty NIO(非阻塞式 io) BIO 你只需要了解网关能做什么? 网关里面写什么代码 就可以了

3. Spring Cloud Gateway工作流程

  1. 客户端向 springcloud Gateway 发出请求
  2. 在 Gateway Handler Mapping 中找到与 请求相匹配的路由,将其发送到 Gateway Web Handler
  3. Handler 再通过指定的过滤器来将请求发送到我们实际的服务的业务逻辑,然后返回。
  4. 过滤器之间用虚线分开是因为过滤器可能会在发送请求之前【pre】或之后【post】执行业务 逻辑,对其进行加强或处理。
    • Filter 在 【pre】 类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转 换等
    • Filter 在【post】 类型的过滤器中可以做响应内容、响应头的修改、日志的输出,流量监控等有着 非常重要的作用。

总结:Gateway 的核心逻辑也就是 路由转发 + 执行过滤器

4. Spring Cloud Gateway 三大核心概念

4.1 Route(路由)(重点 和 eureka 结合做动态路由)

路由信息的组成: 由一个 ID、一个目的 URL、一组断言工厂、一组 Filter 组成。 如果路由断言为真,说明请求 URL 和配置路由匹配。

4.2 Predicate(断言)(就是一个返回 bool 的表达式)

Java 8 中的断言函数。 lambda 四大接口:供给形,消费性,函数型,断言型

Spring Cloud Gateway 中 的 断 言 函 数 输 入 类 型 是 Spring 5.0 框 架 中 的 ServerWebExchange。Spring Cloud Gateway 的断言函数允许开发者去定义匹配来自于 Http Request 中的任何信息比如请求头和参数。

4.3 Filter(过滤) (重点)

一个标准的 Spring WebFilter。 Web 三大组件(servlet listener filter) mvc、interceptor

Spring Cloud Gateway 中的 Filter 分为两种类型的 Filter,分别是 Gateway Filter 和 Global Filter。过滤器 Filter 将会对请求和响应进行修改处理。 一个是针对某一个路由(路径)的 filter 对某一个接口做限流 一个是针对全局的 filter token ip 黑名单

5. Nginx 和 Gateway 的区别

Nginx 在做路由,负载均衡,限流之前,都有修改 nginx.conf 的配置文件,把需要负载均衡, 路由,限流的规则加在里面。Eg:使用 nginx

但是 gateway 不同,gateway 自动的负载均衡和路由,gateway 和 eureka 高度集成,实现 自动的路由,和 Ribbon 结合,实现了负载均衡(lb),gateway 也能轻易的实现限流和权限验证。

Nginx(c)比 gateway(java)的性能高一点。 本质的区别呢?

  • Nginx (更大 服务器级别的)
  • Gateway (项目级别的)

6. Gateway 快速入门

6.1 新建项目,导入依赖

01-gateway-server、02-login-service、03-teacher-service

6.2 模块02-login-service

pom.xml

xml 复制代码
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.zmz</groupId>
    <artifactId>login-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>login-service</name>
    <description>login-service Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
        <spring-cloud.version>Hoxton.SR9</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.12.RELEASE</version>
                <configuration>
                    <mainClass>com.zmz.LoginServiceApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

实体类User.java

java 复制代码
package com.zmz.pojo;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @ProjectName: 04-hystrix
 * @Package: com.zmz.pojo
 * @ClassName: User
 * @Author: 张晟睿
 * @Date: 2022/10/9 14:57
 * @Version: 1.0
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class User {
    private Integer id;
    private String name;
    private String pwd;
    private Integer age;
}

Usercontroller.java

java 复制代码
package com.zmz.controller;

import com.zmz.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.Duration;
import java.util.Random;
import java.util.UUID;

/**
 * @ProjectName: 04-hystrix
 * @Package: com.zmz.controller
 * @ClassName: LoginController
 * @Author: 张晟睿
 * @Date: 2022/10/9 14:59
 * @Version: 1.0
 */
@RestController
public class LoginController {
    @Autowired
    public StringRedisTemplate redisTemplate;


    @GetMapping("doLogin")
    public String doLogin(String name, String pwd) {
        System.out.println(name + " " + pwd);
        User user = new User(1, name, pwd, 23);

        String token = UUID.randomUUID().toString();

        redisTemplate.opsForValue().set(token, user.toString(), Duration.ofSeconds(7200));
        return token;
    }

}

配置application.yml

yml 复制代码
server:
  port: 8088
spring:
  application:
    name: login-service

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
  instance:
    hostname: localhost
    instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}

6.3 网关配置01-gateway-server

yml 复制代码
server:
  port: 80
spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      enabled: true #只要加了依赖,默认开启
      routes:
        - id: login-service-route  #路由id,保持唯一
          uri: http://localhost:8088  #  或者直接使用uri: lb://login-service 来进行动态路由  #uri 统一资源定位符   url统一资源标识符
          predicates:  #断言是给某个路由来做的  断言不能给动态路由来配置,只能在写好的predicates断言内才能生效
            - Path=/doLogin   #断言匹配规则,只要匹配上/doLogin   就往uri转发 并且将路径带上
            - After=2022-10-09T17:18:39.831+08:00[Asia/Shanghai]
            - Method=GET,POST
#            - Query=name,admin.   #正则表达式的值
#            - Path=/mySerivice/**  #多个路径进行匹配
          filters:
            - name: RequestRateLimiter  #这个是过滤器的名称
              args: #过滤器的参数
                key-resolver: '#{@ipKeyResolver}'  #通过spel表达式取IOC容器中的值
                redis-rate-limiter.replenishRate: 1 #生成令牌的速度
                redis-rate-limiter.burstCapacity: 3 #桶容量
      discovery:
        locator:
          enabled: true  #开启动态路由  开启通过业务名称找到对应服务的功能
          lower-case-service-id: true   #服务名称小写开启
#      globalcors:
#          corsConfigurations:
#              '[/**]':
#                  allowCredentials: true  # 可以携带cookie
#                  allowedHeaders: '*'
#                  allowedMethods: '*'
#                  allowedOrigins: '*'
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
    registry-fetch-interval-seconds: 3  #网关拉去服务列表的时间缩短
  instance:
    hostname: localhost
    instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}

6.4 测试

6.5 配置路由

java 复制代码
package com.zmz.config;

import org.springframework.boot.autoconfigure.SpringBootApplication;
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;

import java.time.ZonedDateTime;

/**
 * @ProjectName: 04-hystrix
 * @Package: com.zmz.config
 * @ClassName: RouteConfig
 * @Author: 张晟睿
 * @Date: 2022/10/9 15:24
 * @Version: 1.0
 */
@Configuration
public class RouteConfig {

    /**
     *
     * 代码路由 和 yml不冲突都可以使用
     * @param builder
     * @return
     */
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("test-id", r -> r.path("/nav/web").uri("https://www.csdn.net")) // 地址栏中的地址会变为https://www.csdn.net/nav/web
                .route("openfeign-id", r -> r.path("/nav/ai").uri("https://blog.csdn.net/nav/ai")) //地址栏中的地址会变为http://localhost/nav/ai
                .route("kubernetes-id", r -> r.path("/spring-cloud-kubernetes").uri("https://www.csdn.net")).build();//总结 如果请求的uri中匹配地址包含了访问地址 就不会进行拼接
    }

    public static void main(String[] args) {
        ZonedDateTime now = ZonedDateTime.now();
        System.out.println(now);//2022-10-09T16:18:39.831+08:00[Asia/Shanghai]
    }
}
相关推荐
Bug退退退1234 小时前
RabbitMQ 高级特性之死信队列
java·分布式·spring·rabbitmq
Code季风8 小时前
深入理解微服务中的服务注册与发现(Consul)
java·运维·微服务·zookeeper·架构·go·consul
光军oi8 小时前
java微服务(Springboot篇)——————IDEA搭建第一个Springboot入门项目
java·spring boot·微服务
guojl9 小时前
RestTemplate使用手册
spring cloud·微服务
guojl9 小时前
RestTemplate原理分析
spring cloud·微服务
booooooty9 小时前
基于Spring AI Alibaba的多智能体RAG应用
java·人工智能·spring·多智能体·rag·spring ai·ai alibaba
极光雨雨10 小时前
Spring Bean 控制销毁顺序的方法总结
java·spring
Ken_111510 小时前
SpringCloud系列(51)--SpringCloud Stream之使用分组解决消息重复消费问题
spring cloud
Spirit_NKlaus10 小时前
解决HttpServletRequest无法获取@RequestBody修饰的参数
java·spring boot·spring
LCG元10 小时前
云原生微服务间的异步消息通信:最终一致性与系统容错的架构实战
微服务·云原生·架构