5. SpringCloudAlibab 集成 gateway

news2024/11/26 19:22:04

一、什么是 Spring Cloud Gateway

1、网关简介

网关作为流量的入口,常用的功能包括路由转发,权限校验,限流等等。

SpringCloud Gateway是 Spring Cloud 官方推出的第二代网关框架,定位取代 Netflix Zuul。相对Zuul来说,SpringCloud Gateway 提供更优秀的性能,更强大的功能。

Spring Cloud Gateway是由 WebFlux + Netty + Reactor实现的响应式API网关。

它不能在传统的 servlet容器中工作,也不能构建成war包。

SpringCloud Gateway 旨在为微服务架构提供一种简单且有效的API路由的管理方式,并基于Filter的方式提供网关的基本功能,例如 安全认证、监控、限流等等。

Gateway网关的官方文档地址

2、核心概念

  • 路由(route)
    路由是网关中最基础的部分,路由信息包括一个ID,一个目的URI、一组 谓词工厂、一组Filter组成,如果谓词为真,则说明请求的URL和配置的路由匹配。
  • 谓词(predicates)
    既 java.util.function.Predicate,Spring Cloud Gateway使用 Predicate实现路由的匹配条件
  • 过滤器(Filter)
    Spring Coud Gateway中的 filter分为 Gateway Filter和Global Filter,Filter可以对请求和响应进行处理。
    【路由就是转发规则,谓词就是 是否走这个路径的条件,过滤器可以为路由添加业务逻辑,修改请求以及响应】

例如下面这组代码:

spring:
  cloud:
    nacos:
      routes:
        - id: cloud-product
          uri: lb://cloud-product
          predicates:
            - Path=/product/*
          filters:
            - StripPrefix=1

上面这段routes 配置的就是 只要路径是 product开头的路径就会路由到 cloud-product 这个服务上面去。

3、工作原理

Spring Cloud Gateway的工作原理和Zuul的差不多,最大的区别就是 Gateway的 Filter只有 pre和post两种。

在这里插入图片描述
客户端向Spring Cloud Gateway 发出请求,如果请求与网关程序定义的路由匹配,该请求就会被发送到网关WEB处理,此时处理程序运行特定的请求过滤器链。

过滤器之间用虚线分开的原因是:

过滤器可能在发送请求的前后执行逻辑,所有的pre过滤器逻辑先执行,然后执行代理请求,代理请求完成后,执行post过滤器逻辑。

二、搭建SpringCloud Gateway

2.1 pom文件添加 gateway依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!-- 如果父项目里面引入了 web 那么这里一定要给排除掉 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <!-- 声明依赖的作用范围,依赖的作用范围是 test,表示该依赖仅在测试代码中使用,不会包含在实际的应用程序中。这通常用于引入在测试过程中需要的额外库或工具 -->
            <scope>test</scope>
        </dependency>   

2.2 配置文件中的配置如下

server:
  port: 8999
#测试环境
spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    gateway:
      discovery:
        locator:
          #默认值是false,如果设为true开启通过微服务创建路由的功能,即可以通过微服务名访问服务
          #比如:http://localhost:13001/product-service/product/create
          #不建议打开,因为这样暴露了我们的服务名称:product-service 了
          enabled: false
      #是否开启网关
      enabled: true
      # 路由配置
      routes:
        - id: product-service
          # 这里的uri 你也可以写成 精准的地址  比如下面这里
          # uri: http://localhost:8001/
          uri: lb://product-service
          predicates:
            - Path=/product/**
          filters:
          	# 将路由的前缀去掉1个 也就是去掉 /product
            - StripPrefix=1

表示访问 GATEWAY_URL/product/ 会转发到 product-service 微服务的 /**

三、路由谓词工厂(Route Predicate Factories)配置

谓词工厂官网地址

3.1 谓词工厂的分类

在这里插入图片描述

3.2 时间相关路由

1.After路由断言工厂

规则:

该 断言工厂的参数 是一个UTC格式的时间,将请求访问到Gateway的时间与该时间进行对比,若请求的时间,在参数的范围内则请求放行,否则返回404

spring:
  cloud:
    nacos:
      routes:
        - id: cloud-product
          uri: lb://cloud-product
          predicates:
            - Path=/product/*
             # 当请求的时间 After 配置的时间时,才会转发到用户微服务
			 # 否则不会进该路由配置,所以返回404
			 # 将时间改成 < now的时间,则访问 cloud-product/**
            - After=2030-01-20T17:42:47.789-07:00[America/Denver]

时间可使用

System.out.println(ZonedDateTime.now());

打印,然后就可以看到时区。

2023-06-13T15:55:54.027+08:00[Asia/Shanghai]

2.Before路由断言工厂

这个断言工厂和 After路由断言 类似,after是在设置时间的之后,而before是在设置时间的之前。用法也一样,下面是示例

spring:
  cloud:
    nacos:
      routes:
        - id: cloud-product
          uri: lb://cloud-product
          predicates:
            - Path=/product/*
             # 当请求的时间 Before 配置的时间时,才会转发到用户微服务
			 # 否则不会进该路由配置,所以返回404
			 # 将时间改成 > now的时间,则访问 cloud-product/**
            - Before=2030-01-20T17:42:47.789-07:00[America/Denver]

3.Between路由断言工厂

规则:

工厂从参数是一个开始时间,一个结束时间,判断请求的时间是否在配置这两个时间的范围内,如果在就通过,否则就拒绝。

spring:
  cloud:
    nacos:
      routes:
        - id: cloud-product
          uri: lb://cloud-product
          predicates:
            - Path=/product/*
             # 当且仅当请求时的时间Between配置的时间时,才会转发到用户微服务
			 # 否则不会进该路由配置,所以返回404
            - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2027-01-21T17:42:47.789-07:00[America/Denver]

3.3 Cookie相关路由

1.Cookie路由断言工厂

规则:

工厂包括两个参数,分别是 cookie的key 和 value,判断请求中 是否携带了指定的key 和 value值,如果匹配就通过,否则就拒绝。 值可以设置成正则表达式

spring:
  cloud:
    nacos:
      routes:
        - id: cloud-product
          uri: lb://cloud-product
          predicates:
            - Path=/product/*
             # 当请求带有 bigcookie,并且值是 product-oo时,才会转发到微服务
			 # 否则不会进该路由配置,所以返回404
            - Cookie=bigcookie,product-oo

3.4 Header相关路由

1.header路由断言工厂

规则:

包含两个参数,分别是请求头 header里面的 key和 value,请求携带了指定的key和value通过,否则拒绝。值可以设置成正则表达式

spring:
  cloud:
    nacos:
      routes:
        - id: cloud-product
          uri: lb://cloud-product
          predicates:
            - Path=/product/*
             # 当请求的请求头中 有名为 X-Request-area,并且值是hb,才会转发到服务
			 # 否则不会进该路由配置,所以返回404
			 # 
            - Header=X-Request-area,hb

3.5 请求相关路由

1. Host路由断言工厂

规则:

请求头中的 Host属性,是否是配置文件中指定的Host属性值,如果是,通过。否则失败。

spring:
  cloud:
    nacos:
      routes:
        - id: cloud-product
          uri: lb://cloud-product
          predicates:
            - Path=/product/*
             # 判断请求头中的Host 是否符合 **.666.org 或 **.abcd.org,如果符合转发到相关服务中
			 # 否则不会进该路由配置,所以返回404
            - Host=**.666.org,**.abcd.org

2. Method路由断言工厂

规则:

判断请求是否使用了指定方法,POST还是GET或者其他类型的请求。匹配就通过,否则就拒绝。

spring:
  cloud:
    nacos:
      routes:
        - id: cloud-product
          uri: lb://cloud-product
          predicates:
            - Path=/product/*
             # 当HTTP请求是GET时,才会转发到微服务中
			 # 否则不会进该路由配置,所以返回404
            - Method=GET

3. Path路由断言工厂

规则:

判断请求路径是否包含指定的uri,若包含,则通过,否则拒绝。

spring:
  cloud:
    nacos:
      routes:
        - id: cloud-product
          uri: lb://cloud-product
          predicates:
            - Path=/product/*
             # 当访问路径是 /product/* 或者/sim-product/**,才会转发请求到微服务中
			 # 否则不会进该路由配置,所以返回404
            - Path=/product/{segment},/sim-product/**

4. Query路由断言工厂

规则:

在请求中查找指定的请求参数,可以只设置参数名称,也可以同时设置参数的名称和值。匹配就通过,否则就拒绝。

参数:
param 请求参数的key值
regexp 请求参数的值,配置的值是 JAVA中的 正则表达式

spring:
  cloud:
    nacos:
      routes:
        - id: cloud-product
          uri: lb://cloud-product
          predicates:
            - Path=/product/*
             # 当请求带有 bba的参数时,才会转发到微服务中
			 # 否则不会进该路由配置,所以返回404
			 # 例如 localhost:8999/product/flash/killing?bba=111 这样才会转发到对应的服务中
            - Query=bba
            # 当且仅当请求带有名为bba的参数,且参数值符合正则ba.,才会转发到微服务 例如 localhost:8999/product/flash/killing?bba=bca
            - Query=bba, bc.

5. Weight路由断言工厂

规则:

包含两个参数,分别是用于表示组 group,权重 weight,对于同一组多个uri地址,会根据权重的值来进行请求的指向。

spring:
  cloud:
    nacos:
      routes:
        - id:  weight_high
          uri: http://localhost:8081/
          predicates:
          	- Path=/order/**
            - Weight=group1, 8
        - id:  weight_low
          uri: http://localhost:8082/
          predicates:
          	- Path=/order/**
            - Weight=group1, 2

比如上面 weight_high的权重是8,那么请求会优先给到 weight_high,然后部分请求会给到weight_low。

3.6 自定义谓词工厂实战

比如我们现在有个秒杀场景,秒杀的开始时间是 晚上的9点到 9点10分。限制 21:00 - 21:10 才能访问我们的 product/flash/killing 接口。

假如我们自定义个 FlashKillingTime= 下午09:00,下午09:10

spring:
  cloud:
    nacos:
      routes:
        - id: cloud-product
          uri: lb://cloud-product
          predicates:
            - Path=/product/*
            # 只有在 下午9点 到 下午的 9点10分才能进行访问
            - FlashKillingTime= 下午09:00,下午09:10

自定义路由断言工厂需要继承 AbstractRoutePredicateFactory类,重写apply方法的逻辑。

自定义路由工厂的命名 必须以 RoutePredicateFactory 结尾。

1.创建参数配置文件 FlashKillingTimeConfig

import lombok.Data;

import java.time.LocalTime;

@Data
public class FlashKillingTimeConfig {
    /**
     * 接收开始时间
     */
    private LocalTime start;

    /**
     * 接收结束时间
     */
    private LocalTime end;
}

2.创建 FlashKillingTimeRoutePredicateFactory文件

import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

import java.time.LocalTime;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

/**
 * 时间判断断言工厂类
 */
@Component
public class FlashKillingTimeRoutePredicateFactory extends AbstractRoutePredicateFactory<FlashKillingTimeConfig> {


    public FlashKillingTimeRoutePredicateFactory() {
        super(FlashKillingTimeConfig.class);
    }

    /**
     * 进行判断逻辑代码
     * @param config
     * @return
     */
    @Override
    public Predicate<ServerWebExchange> apply(FlashKillingTimeConfig config) {
        LocalTime start = config.getStart();
        LocalTime end = config.getEnd();
        return new Predicate<ServerWebExchange>() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                String uri = serverWebExchange.getRequest().getURI().getPath();
                if (uri.equals("/product/flash/killing")) {
                    LocalTime now = LocalTime.now();
                    return now.isAfter(start) && now.isBefore(end);
                }
                return true;
            }
        };
    }

    /**
     * 配置文件中的参数 下午09:00,下午09:10  相当于
     *                   start   , end
     * 如果需要多个参数 那么后面还可以添加就好了
     * 这里面的名称 也一定要和 我们实体类里面 定义的名称一样
     * 
     * 用来映射参数,asList("配置文件的第1个参数","配置文件的第2个参数","配置文件的第3个参
     * 数","配置文件的第4个参数"....),接给配置类。
     * @return
     */
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("start", "end");
    }


}

四、过滤器工厂( GatewayFilter Factories)配置

SpringCloudGateway 内置了很多的过滤器工厂,我们通过一些过滤器工厂可以进行一些业务逻辑。比如添加、剔除响应头,添加去除参数等等。

SpringCloudGateway官网
官方内置的过滤器很多,如果需要其他的请去官方看下,这里列举以下平常使用的较多的。

1.内置过滤工厂类

1. AddRequestHeader 过滤工厂

spring:
  cloud:
    nacos:
      routes:
        - id: cloud-product
          uri: lb://cloud-product
          predicates:
            - Path=/product/*
		  filters:
 			- AddRequestHeader=X-Request-Foo, Bar

为原始请求添加名为 X-Request-Foo ,值为 Bar 的请求头。

2. AddRequestParameter 过滤工厂

spring:
  cloud:
    nacos:
      routes:
        - id: cloud-product
          uri: lb://cloud-product
          predicates:
            - Path=/product/*
		  filters:
 			- AddRequestParameter=foo, bar

为原始请求添加请求参数 foo=bar

3. AddResponseHeader 过滤工厂

spring:
  cloud:
    nacos:
      routes:
        - id: cloud-product
          uri: lb://cloud-product
          predicates:
            - Path=/product/*
		  filters:
 			- AddResponseHeader=X-Response-Foo, Bar

添加名为 X-Request-Foo ,值为 Bar 的响应头。

4.PrefixPath 过滤工厂

spring:
  cloud:
    nacos:
      routes:
        - id: cloud-product
          uri: lb://cloud-product
          predicates:
            - Path=/product/*
		  filters:
 			- PrefixPath=/mypath

为匹配的路由添加前缀。
例如:访问 ${GATEWAY_URL}/product 会转发到 https://example.org/mypath/product

5. RequestRateLimiter 过滤工厂

spring:
  cloud:
    nacos:
      routes:
        - id: cloud-product
          uri: lb://cloud-product
          predicates:
            - Path=/product/*
          filters:
            - name: RequestRateLimiter
            args:
              redis-rate-limiter.replenishRate: 10
              redis-rate-limiter.burstCapacity: 20

设置请求的限流,这里的限流是使用的redis

6.StripPrefix 过滤工厂

spring:
  cloud:
    nacos:
      routes:
        - id: cloud-product
          uri: lb://cloud-product
          predicates:
            - Path=/product/*
          filters:
			- StripPrefix=2

数字表示要截断的路径的数量。
如上配置,如果请求的路径为 /product/bar/foo ,则路径会修改为 /foo ,也就是会截断2个路径。

2.自定义过滤器实战

自定义过滤器分为两种:

  1. 局部过滤器:AbstractNameValueGatewayFilterFactory子类则需要在使用路由配置的时候,明确指定需要使用的过滤器名称和相关参数。
  2. 全局过滤器:实现GlobalFilter的过滤器会被应用到所有的路由中

2.1 局部过滤器实现:

2.2 全局过滤器实现:

1.创建 IPAddressStatisticsFilter 记录客户端ip地址的访问次数:

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.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 记录当前ip访问的次数
 */
@Component
@Slf4j
public class IPAddressStatisticsFilter implements GlobalFilter, Ordered {

    public static final Map<String, AtomicInteger> CACHE = new ConcurrentHashMap<>();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //获取客户端的ip地址
        InetSocketAddress host = exchange.getRequest().getHeaders().getHost();
        //如果获取不到 返回 400 错误
        if (host == null || host.getHostName() == null) {
            exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
            return exchange.getResponse().setComplete();
        }
        //否则的话 记录当前ip访问次数
        String hostName = host.getHostName();
        AtomicInteger count = CACHE.getOrDefault(hostName, new AtomicInteger(0));
        count.incrementAndGet();
        CACHE.put(hostName, count);
        log.info("IP地址:" + hostName + ",访问次数:" + count.intValue());
        return chain.filter(exchange);

    }

    /**
     * order的值越小,当前过滤器加载的顺序 就越先被执行
     * 越小越靠前  越大越靠后
     *
     * @return
     */
    @Override
    public int getOrder() {
        return -1;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/643486.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【多线程】原子引用ABA问题

目录 一、代码示例二、执行结果截图三、说明四、AtomicStampedReference使用4.1 代码示例4.2 截图 一、代码示例 package com.learning.atomic;import lombok.extern.slf4j.Slf4j; import java.util.concurrent.atomic.AtomicReference; /*** Author wangyouhui* Description …

2023年软考-高级信息系统项目管理工程师考试大纲

高级信息系统项目管理工程师考试大纲 2023年软考高级信息系统项目管理工程师考试大纲已于2023年5月出版。您可以在 中国计算机技术职业资格网 上找到更多关于考试的信息 。 信息系统项目管理师是对从事信息系统项目管理工作的专业技术人员基本理论和实践能力的综合考核,该专业…

新手如何挑选一款合适的功率放大器?

ATA系列功率放大器是&#xff08;AB&#xff09;类功放&#xff0c;相比于甲类功率放大器&#xff0c;它小信号输入时效率更高&#xff0c;随着输出功率的增大&#xff0c;效率也增高&#xff0c;它的效率比以及保真度而言&#xff0c;都优于A类和B类功放。 因为具有这些优势&a…

助你更好的理解 Python 字典

助你更好的理解 Python 字典 字典是Python中的常用数据类型之一&#xff0c;可将数据存储在键/值对中&#xff0c;同 Java 中的 Map 相似。 1、什么是字典理解&#xff1f; 字典理解是创建字典的一种优雅简洁的方法。 字典理解优化 使用字典理解优化函数。 示例&#xff…

使用 FFmpeg 开发的那些事

勇敢就是&#xff0c;在你还没开始的时候就知道自己注定会输&#xff0c;但依然义无反顾地去做&#xff0c;并且不管发生什么都坚持到底。一个人很少能赢&#xff0c;但也总会有赢的时候。《杀死一只知更鸟》 欢迎大家加入广州城市社区&#xff1a;https://devpress.csdn.net/g…

java面经

String, StringBuffer, StringBuilder区别 第一点是可变性。String不可变&#xff0c;String Buffer和StringBuider可变。这是因为String被final修饰&#xff0c;每次操作都生成新的对象。StringBuffer和StringBuilder的父类AbstractStringBuilder没有被final修饰。 第二点是…

MATLAB 之 非线性方程数值求解、最优化问题求解和常微分方程初值问题的数值求解

这里写目录标题 一、非线性方程数值求解1. 单变量非线性方程求解2. 非线性方程组的求解 二、最优化问题求解1. 无约束最优化问题求解2. 有约束最优化问题求解3. 线性规划问题求解 三、常微分方程初值问题的数值求解1. 龙格—库塔法简介2. 龙格—库塔法的实现 一、非线性方程数值…

Day975.如何使用JWT结构化令牌 -OAuth 2.0

如何使用JWT结构化令牌 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于如何使用JWT结构化令牌的内容。 OAuth 2.0 规范并没有约束访问令牌内容的生成规则&#xff0c;只要符合唯一性、不连续性、不可猜性就够了。这就意味着&#xff0c;可以灵活选择令牌的形式&…

将递归函数转成非递归函数的通用方法

看到过一道非常不错的面试题&#xff1a;不支持递归的程序语言如何实现递归程序&#xff1f; 之所以说这道题好&#xff0c;是因为&#xff1a; 首先&#xff0c;它不是纯粹考概念和死记硬背&#xff0c;求职者在回答问题之前需要进行一定的思考&#xff1b; 其次&#xff0c…

vim粘贴出现多余的#

vim粘贴yaml格式时&#xff0c;出现多余的#&#xff0c;格式错误 解决&#xff1a;设置paste :set paste 然后再粘贴即可

final不可变性

一、什么是不可变性&#xff08;Immutable&#xff09; 如果对象在被创建后&#xff0c;状态就不能被修改&#xff0c;那么它就是不可变的这个对象不能被修改指&#xff1a; 对象指向(引用)不可变字段不可变成员变量不可变 案列演示&#xff1a; person对象&#xff0c;age和…

我的C++学习笔记

声明&#xff1a; 写本篇博客的目的是为了整理自己在找工作时学习的C相关知识点&#xff0c;博客整体内容会分为两种风格&#xff0c;第一章基础部分是以常见C面试问题解答的形式呈现&#xff1b;其余部分是知识点层层递进的方式展现&#xff0c;比较系统。其中&#xff0c;在第…

Avalon 学习系列(三)—— 数据和指令同步

Avalon 有很多个指令&#xff0c;通过这些指令可以对 DOM 进行一些事件操作、或者样式修改。 ms-duplex Avalon 实现数据与视图的同步的方式是用 ms-duplex 将元素跟数据绑定在一起&#xff0c;如果有其中一个的值改变另一个值也将改变。 ms-duplex 是 avalon 的双向绑定属性…

OpenCV(C++)创建图片绘制图形(矩形、圆、文字、线段等等)

一、OpenCV介绍 OpenCV 是基于开源许可证的跨平台计算机视觉库,提供了一组丰富、广泛的图像处理和计算机视觉算法。OpenCV 支持多种编程语言,包括 C++、Python、Java 等,可以运行在 Linux、Windows、Mac OS 等平台上。 OpenCV 能够在图像上绘制各种几何形状、文本和曲线,…

学习ESP32笔记

学习ESP32笔记 1.platform IO插件的下载&#xff08;提前安装好python&#xff0c;不然在中间的一部分会一直报错&#xff09; VS Code下载platform IO时&#xff0c;开加速器&#xff08;VPN&#xff09;&#xff0c;并且关闭防火墙 这一步比较慢&#xff0c;大概等十来分钟…

Kendo UI for jQuery---02.开始---01.使用 Kendo UI for jQuery 的第一步

使用 Kendo UI for jQuery 的第一步 欢迎来到 Kendo UI for jQuery 入门的第一步指南&#xff01; 本指南演示如何通过添加所需资源和初始化 Kendo UI 网格来开始使用套件。 该过程借鉴了以下里程碑&#xff1a; 1.下载控件 2.添加所需的 JavaScript 和 CSS 文件 3.将网格绑…

如何使用postman做接口测试

常用的接口测试工具主要有以下几种&#xff1a; Postman: 简单方便的接口调试工具&#xff0c;便于分享和协作。具有接口调试&#xff0c;接口集管理&#xff0c;环境配置&#xff0c;参数化&#xff0c;断言&#xff0c;批量执行&#xff0c;录制接口&#xff0c;Mock Server…

【每日挠头算法题(6)】二叉树的所有路径|神奇字符串

欢迎~ 一、二叉树的所有路径思路&#xff1a;深度优先搜索具体代码如下&#xff1a; 二、神奇字符串思路&#xff1a;模拟双指针具体代码如下&#xff1a; 总结 一、二叉树的所有路径 点我直达~ 思路&#xff1a;深度优先搜索 使用深度优先搜索&#xff1a;即二叉树的前序遍历…

设计模式(十二):结构型之享元模式

设计模式系列文章 设计模式(一)&#xff1a;创建型之单例模式 设计模式(二、三)&#xff1a;创建型之工厂方法和抽象工厂模式 设计模式(四)&#xff1a;创建型之原型模式 设计模式(五)&#xff1a;创建型之建造者模式 设计模式(六)&#xff1a;结构型之代理模式 设计模式…

编码生成矩阵与检错监督矩阵

本专栏包含信息论与编码的核心知识&#xff0c;按知识点组织&#xff0c;可作为教学或学习的参考。markdown版本已归档至【Github仓库&#xff1a;https://github.com/timerring/information-theory 】或者公众号【AIShareLab】回复 信息论 获取。 文章目录 线性分组码基本概念…