springcloud简单概要

本文最后更新于:2022年8月17日 上午

本文不涉及具体的代码和组件的使用方式, 只是简单阅读springcloud的2021.0.2版本的文档并做一些笔记.

spring-cloud document versions

before

官方文档链接: https://docs.spring.io/spring-cloud/docs/current/reference/html/

Spring Cloud provides tools for developers to quickly build some of the common patterns in distributed systems (e.g. configuration management, service discovery, circuit breakers, intelligent routing, micro-proxy, control bus). Coordination of distributed systems leads to boiler plate patterns, and using Spring Cloud developers can quickly stand up services and applications that implement those patterns. They will work well in any distributed environment, including the developer’s own laptop, bare metal data centres, and managed platforms such as Cloud Foundry.

Release Train Version: 2021.0.2

Supported Boot Version: 2.6.7

译: Spring Cloud为开发者提供了快速构建分布式系统中一些常见模式的工具(如配置管理、服务发现、断路器、智能路由、微代理、控制总线)。分布式系统的协调导致了”锅炉板模式”,使用Spring Cloud,开发者可以快速建立实现这些模式的服务和应用。它们在任何分布式环境中都能很好地工作,包括开发人员自己的笔记本电脑、裸机数据中心和管理平台,如Cloud Foundry。

  • 关于锅炉板模式(boiler plate patterns)

    样板式代码即Boilerplate code, 所谓boiler plate patterns, 实际上就是指spring cloud为开发者提供了一种样板式的开发模式, 使开发者只需要根据样板结构来开发微服务节点即可.

springcloud的features

Spring Cloud focuses on providing good out of box experience for typical use cases and extensibility mechanism to cover others.

  • Distributed/versioned configuration 分布式和版本化的配置
  • Service registration and discovery 服务注册和服务发现
  • Routing 路由
  • Service-to-service calls 服务调用
  • Load balancing 负载均衡
  • Circuit Breakers 断路器
  • Distributed messaging 分布式消息传递

springcloud的组件

The reference documentation consists of the following sections:

组件 信息
Documentation Overview About the Documentation, Getting Help, First Steps, and more.
spring-cloud-build spring-cloud-build Reference Documentation, version 3.1.2
spring-cloud-bus spring-cloud-bus Reference Documentation, version 3.1.0
spring-cloud-circuitbreaker spring-cloud-circuitbreaker Reference Documentation, version 2.1.2
spring-cloud-cli spring-cloud-cli Reference Documentation, version 3.1.0
spring-cloud-cloudfoundry spring-cloud-cloudfoundry Reference Documentation, version 3.1.0
spring-cloud-commons spring-cloud-commons Reference Documentation, version 3.1.2
spring-cloud-config spring-cloud-config Reference Documentation, version 3.1.2
spring-cloud-consul spring-cloud-consul Reference Documentation, version 3.1.0
spring-cloud-contract spring-cloud-contract Reference Documentation, version 3.1.2
spring-cloud-function spring-cloud-function Reference Documentation, version 3.2.4
spring-cloud-gateway spring-cloud-gateway Reference Documentation, version 3.1.2
spring-cloud-kubernetes spring-cloud-kubernetes Reference Documentation, version 2.1.2
spring-cloud-netflix spring-cloud-netflix Reference Documentation, version 3.1.2
spring-cloud-openfeign spring-cloud-openfeign Reference Documentation, version 3.1.2
spring-cloud-sleuth spring-cloud-sleuth Reference Documentation, version 3.1.2
spring-cloud-stream spring-cloud-stream Reference Documentation, version 3.2.3
spring-cloud-task spring-cloud-task Reference Documentation, version 2.4.2
spring-cloud-vault spring-cloud-vault Reference Documentation, version 3.1.0
spring-cloud-zookeeper spring-cloud-zookeeper Reference Documentation, version 3.1.1

概述 Overview

官方文档的阅读形式

获取帮助的方式

Spring Cloud Build

github: https://github.com/spring-cloud/spring-cloud-build

文档: https://docs.spring.io/spring-cloud-build/docs/3.1.2/reference/html/

Spring Cloud Build是Spring Cloud用于插件和依赖性管理的一个通用工具项目。

Spring Cloud Bus (消息总线)

github: https://github.com/spring-cloud/spring-cloud-bus

文档: https://docs.spring.io/spring-cloud-bus/docs/3.1.0/reference/html/

简介

Spring Cloud Bus links the nodes of a distributed system with a lightweight message broker. This broker can then be used to broadcast state changes (such as configuration changes) or other management instructions. A key idea is that the bus is like a distributed actuator for a Spring Boot application that is scaled out. However, it can also be used as a communication channel between apps. This project provides starters for either an AMQP broker or Kafka as the transport.

译:

Spring Cloud Bus将分布式系统的节点与一个轻量级的消息代理联系起来。然后,这个代理可以用来广播状态变化(如配置变化)或其他管理指令。一个关键的想法是,总线就像Spring Boot应用的一个分布式执行器,是可以扩展的。然而,它也可以被用作应用程序之间的通信渠道。这个项目提供了AMQP代理Kafka作为传输的启动器。

简单来说, bus就是一个可以通过广播方式引发节点状态刷新的工具, 底层基于spring cloud stream实现

其支持两种消息中间件:

  • Rabbit MQ
  • Kafka
  • 关于AMQP broker:

    AMQP(Advanced Message Queuing Protocol)是一种消息队列协议标准,为面向消息的中间件设计。 基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。

    目前基于AMQP开发并且使用量较大的几乎唯一的消息中间件就是Rabbit MQ.

使用

文档中给出的quick start包括描述了如下的使用功能:

Spring Cloud Circuit Breaker (断路器)

github: https://github.com/spring-cloud/spring-cloud-circuitbreaker

文档: https://docs.spring.io/spring-cloud-circuitbreaker/docs/2.1.2/reference/html

Spring Cloud 2020 版本之后废弃了对大部分 Netflix 组件的支持,其中就包括最常用的断路器组件 Hystrix,取而代之的就是 resilience4j, sentinel , Spring Retry 等Spring Cloud Circuit Breaker项目包含了对其中的resilience4j以及Spring Retry的实现.

Spring Boot Cloud cli

Spring Boot CLI provides Spring Boot command line features for Spring Cloud. You can write Groovy scripts to run Spring Cloud component applications (e.g. @EnableEurekaServer). You can also easily do things like encryption and decryption to support Spring Cloud Config clients with secret configuration values. With the Launcher CLI you can launch services like Eureka, Zipkin, Config Server conveniently all at once from the command line (very useful at development time).

译:

Spring Boot CLI为Spring Cloud提供Spring Boot命令行功能。你可以编写Groovy脚本来运行Spring Cloud组件应用程序(例如@EnableEurekaServer)。你还可以轻松地进行加密和解密等工作,以支持具有秘密配置值的Spring Cloud Config客户端。通过Launcher CLI,你可以从命令行一次性方便地启动Eureka、Zipkin、Config Server等服务(在开发时非常有用)。

Spring Cloud for Cloud Foundry

Spring Cloud for Cloudfoundry makes it easy to run Spring Cloud apps in Cloud Foundry (the Platform as a Service). Cloud Foundry has the notion of a “service”, which is middlware that you “bind” to an app, essentially providing it with an environment variable containing credentials (e.g. the location and username to use for the service).

译:

Spring Cloud for Cloudfoundry 使得在 Cloud Foundry(平台即服务)中运行 Spring Cloud 应用程序变得容易。Cloud Foundry 有一个 “服务 “的概念,它是你 “绑定 “一个应用程序的中间件,本质上是向它提供一个包含证书的环境变量(例如,用于服务的位置和用户名)。

这个好像用的人不多

Spring Cloud Commons

文档: https://docs.spring.io/spring-cloud-commons/docs/3.1.2/reference/html/

简介

该部分介绍了spring cloud最基础的一些内容, 包括

The Bootstrap Application Context (上下文和环境配置的方案)

  • 上下文(context)层级介绍:
    • bootstrap 上下文
    • application 上下文
  • bootstrap的配置
  • 日志配置
  • 环境更改和配置变化
  • 加密解密
  • 端点

Spring Cloud Commons: Common Abstractions (通用抽象)

  • 服务发现
  • 负载均衡
  • 断路器

Security (登录与令牌中继)

Spring Cloud Config(分布式配置中心)

文档: https://docs.spring.io/spring-cloud-config/docs/3.1.2/reference/html/#_quick_start

Spring Cloud Config provides server-side and client-side support for externalized configuration in a distributed system. With the Config Server, you have a central place to manage external properties for applications across all environments. The concepts on both client and server map identically to the Spring Environment and PropertySource abstractions, so they fit very well with Spring applications but can be used with any application running in any language. As an application moves through the deployment pipeline from dev to test and into production, you can manage the configuration between those environments and be certain that applications have everything they need to run when they migrate. The default implementation of the server storage backend uses git, so it easily supports labelled versions of configuration environments as well as being accessible to a wide range of tooling for managing the content. It is easy to add alternative implementations and plug them in with Spring configuration.

译:

Spring Cloud Config为分布式系统中的外部化配置提供服务器端和客户端支持。有了配置服务器,你就有了一个集中的地方来管理所有环境中的应用程序的外部属性。客户端和服务器上的概念与Spring环境和PropertySource抽象完全一致,因此它们非常适用于Spring应用程序,但也可用于以任何语言运行的任何应用程序。当应用程序通过部署管道从开发到测试再到生产时,你可以管理这些环境之间的配置,并确保应用程序在迁移时拥有它们需要的一切。服务器存储后端的默认实现使用git,所以它很容易支持配置环境的标记版本,以及可用于管理内容的各种工具。很容易添加其他的实现,并将它们与Spring配置连接起来。

简而言之, 就是采用一个server端通过git等方式保存配置文件, 然后通过client端读取配置文件

Spring Cloud Consul

文档: https://docs.spring.io/spring-cloud-consul/docs/3.1.0/reference/html/

This project provides Consul integrations for Spring Boot apps through autoconfiguration and binding to the Spring Environment and other Spring programming model idioms. With a few simple annotations you can quickly enable and configure the common patterns inside your application and build large distributed systems with Consul based components. The patterns provided include Service Discovery, Control Bus and Configuration. Intelligent Routing and Client Side Load Balancing, Circuit Breaker are provided by integration with other Spring Cloud projects.

译:

该项目通过自动配置和与Spring环境及其他Spring编程模型习语的绑定,为Spring Boot应用程序提供Consul集成。通过一些简单的注解,你可以在你的应用程序中快速启用和配置通用模式,并使用基于Consul的组件构建大型分布式系统。提供的模式包括服务发现、控制总线和配置。通过与其他Spring Cloud项目的集成,提供了智能路由和客户端负载均衡、断路器。

简介

该部分介绍了consul与spring cloud结合配置的一些基本信息, 包括:

  • consul的安装和配置
  • 服务发现的激活, 注册, 发现, 变更管理等
  • 如何用 spring-cloud-consul 替代 spring-cloud-config
  • retry
  • 与spring-cloud-bus的集成
  • 与hystrix断路器的集成

Spring Cloud Contract

文档: https://docs.spring.io/spring-cloud-contract/docs/3.1.2/reference/html/getting-started.html#getting-started-introducing-spring-cloud-contract

Spring Cloud Contract moves TDD to the level of software architecture. It lets you perform consumer-driven and producer-driven contract testing.

译:

Spring Cloud Contract将TDD移到了软件架构的层面。它可以让你执行消费者驱动和生产者驱动的合同测试。

TDD: test-driven development, 测试驱动开发, TDD的原理是在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码。

CDC: 消费者驱动的契约测试(Consumer-Driven Contracts,简称CDC),是指从消费者业务实现的角度出发,驱动出契约,再基于契约,对提供者验证的一种测试方式。

spring-cloud-contract就是一个spring cloud提供的CDC框架

Spring Cloud Function

文档: https://docs.spring.io/spring-cloud-function/docs/3.2.4/reference/html/spring-cloud-function.html#_introduction

Spring Cloud Function is a project with the following high-level goals:

  • Promote the implementation of business logic via functions.
  • Decouple the development lifecycle of business logic from any specific runtime target so that the same code can run as a web endpoint, a stream processor, or a task.
  • Support a uniform programming model across serverless providers, as well as the ability to run standalone (locally or in a PaaS).
  • Enable Spring Boot features (auto-configuration, dependency injection, metrics) on serverless providers.

译:

Spring Cloud Function 是一个具有以下高级目标的项目:

  • 通过函数促进业务逻辑的实现。
  • 将业务逻辑的开发生命周期与任何特定的运行时目标分离,以便相同的代码可以作为 Web 端点、流处理器或任务运行。
  • 支持跨无服务器提供商的统一编程模型,以及独立运行(本地或在 PaaS 中)的能力。
  • 在无服务器提供程序上启用 Spring Boot 功能(自动配置、依赖注入、指标)。

Spring Cloud Gateway(网关)

This project provides an API Gateway built on top of the Spring Ecosystem, including: Spring 5, Spring Boot 2 and Project Reactor. Spring Cloud Gateway aims to provide a simple, yet effective way to route to APIs and provide cross cutting concerns to them such as: security, monitoring/metrics, and resiliency.

译:

这个项目提供了一个建立在Spring生态系统之上的API网关,包括。Spring 5、Spring Boot 2和Project Reactor。Spring Cloud Gateway旨在提供一种简单而有效的方式来路由到API,并为它们提供交叉关注,如:安全、监控/指标和弹性。

网关的作用:

对于来自外部的用户请求来说,在处理请求的核心业务逻辑之前,一般还需要对请求做一些预处理,如权限校验、监控统计、流量限制等。如果外部请求直接到达微服务,那么所有的服务都需要各自负责处理这些功能,会造成这部分功能逻辑在各个服务重复出现,增加了未来对这些基础功能的维护升级的成本。

所以在微服务环境下,我们还需要一个网关组件来作为请求入口。一些基础的请求预处理的逻辑可以统一实现在网关这一层,这样业务服务只需要专注于处理业务逻辑即可。另外,引入网关作为统一请求入口之后,还可以利用网关来实现一些其他的功能,比如服务保护、灰度发布等。[1]

spring-cloud-gateway的优势:

在 Spring Cloud Gateway 发布之前,Spring Cloud 使用的是由 Netflix 开源的 Zuul 1 作为网关组件。Zuul 1 是基于传统的 Servlet API 开发的,使用了阻塞的网络模型,每个请求需要分配专门的线程处理,所以资源开销比较大,在高并发的情况下需要创建大量的线程来处理请求,线程数目会成为系统的瓶颈。作为取代 Spring Cloud Zuul 的组件,Spring Cloud Gateway 网络层使用了基于非阻塞的 Netty,解决了线程数瓶颈从而提升了系统性能。

ps: 这部分也可以看看b站上尚硅谷的简单介绍: https://www.bilibili.com/video/BV18E411x7eT?p=66\

简介

核心概念介绍

gateway主要由以下几个核心概念

  • Route: The basic building block of the gateway. It is defined by an ID, a destination URI, a collection of predicates, and a collection of filters. A route is matched if the aggregate predicate is true.
  • Predicate: This is a Java 8 Function Predicate. The input type is a Spring Framework ServerWebExchange. This lets you match on anything from the HTTP request, such as headers or parameters.
  • Filter: These are instances of GatewayFilter that have been constructed with a specific factory. Here, you can modify requests and responses before or after sending the downstream request.
  • Route: 一个 Route 由路由 ID,转发 URI,多个 Predicates 以及多个 Filters 构成。Gateway 上可以配置多个 Routes。处理请求时会按优先级排序,找到第一个满足所有 Predicates 的 Route。
  • Predicate: 表示路由的匹配条件,可以用来匹配请求的各种属性,如请求路径、方法、header 等。一个 Route 可以包含多个子 Predicates,多个子 Predicates 最终会合并成一个。
  • Filter: 过滤器包括了处理请求和响应的逻辑,可以分为 pre 和 post 两个阶段。多个 Filter 在 pre 阶段会按优先级高到低顺序执行,post 阶段则是反向执行。Gateway 包括两类 Filter
    • 全局 Filter: 每种全局 Filter 全局只会有一个实例,会对所有的 Route 都生效。
    • 路由 Filter: 路由 Filter 是针对 Route 进行配置的,不同的 Route 可以使用不同的参数,因此会创建不同的实例。[1]

功能

  • route predicate factories(不知道咋翻译, 路由匹配谓词工厂?): 处理匹配HTTP请求的属性, 包括:

  • GatewayFilter factories: 根据输入http请求或者输出http响应返回一个特定的路由, 如: 添加路由前缀, 添加header信息, 修改http状态码等等, 具体文档里列举了很多

  • Global Filters: 适用于所有的路由的filters,

  • HttpHeadersFilters: 在将请求发送到下游服务时应用

  • 超时, 跨域(CORS), 等等..

Spring Cloud Kubernetes

文档: https://docs.spring.io/spring-cloud-kubernetes/docs/2.1.2/reference/html/

Spring Cloud Kubernetes provides implementations of well known Spring Cloud interfaces allowing developers to build and run Spring Cloud applications on Kubernetes. While this project may be useful to you when building a cloud native application, it is also not a requirement in order to deploy a Spring Boot app on Kubernetes. If you are just getting started in your journey to running your Spring Boot app on Kubernetes you can accomplish a lot with nothing more than a basic Spring Boot app and Kubernetes itself. To learn more, you can get started by reading the Spring Boot reference documentation for deploying to Kubernetes and also working through the workshop material Spring and Kubernetes.

译:

Spring Cloud Kubernetes提供了众所周知的Spring Cloud接口的实现,允许开发者在Kubernetes上构建和运行Spring Cloud应用。虽然这个项目在构建云原生应用时可能对你有用,但它也不是在Kubernetes上部署Spring Boot应用的必要条件。如果你刚刚开始在Kubernetes上运行你的Spring Boot应用,你只需要一个基本的Spring Boot应用和Kubernetes本身就可以完成很多事情。

Spring Cloud Netflix

文档: https://docs.spring.io/spring-cloud-netflix/docs/3.1.2/reference/html/#service-discovery-eureka-clients

This project provides Netflix OSS integrations for Spring Boot apps through autoconfiguration and binding to the Spring Environment and other Spring programming model idioms. With a few simple annotations you can quickly enable and configure the common patterns inside your application and build large distributed systems with battle-tested Netflix components. The patterns provided include Service Discovery (Eureka).

译:

该项目通过自动配置和与Spring环境及其他Spring编程模型成语的绑定,为Spring Boot应用程序提供Netflix OSS集成。通过一些简单的注解,你可以在你的应用程序中快速启用和配置常见的模式,并用经过实战检验的Netflix组件构建大型分布式系统。所提供的模式包括服务发现(Eureka)。

主要还是包括了对eureka的集成, 但是现在服务发现一般用consul

Spring Cloud OpenFeign

文档: https://docs.spring.io/spring-cloud-openfeign/docs/3.1.2/reference/html/

This project provides OpenFeign integrations for Spring Boot apps through autoconfiguration and binding to the Spring Environment and other Spring programming model idioms.

译:

该项目通过自动配置和与Spring环境及其他Spring编程模型习语的绑定,为Spring Boot应用提供OpenFeign集成。

openfeign用于实现微服务之间的调用

feign和openfeign

Feign 是一个声明式 Web 服务客户端。

Feign 与 OpenFeign的区别:Feign是Springcloud组件中的一个轻量级Restful的HTTP服务客户端,Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务;OpenFeign是springcloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

功能

  • 引入feign
  • 配置覆盖
  • 如何自行创建feign client
  • 断路器包装
  • 继承
  • gzip压缩
  • 日志

Spring Cloud Stream

文档: https://docs.spring.io/spring-cloud-stream/docs/3.2.3/reference/html/

作用:

  • 在实际开发过程中,服务与服务之间通信经常会使用到消息中间件,如果我们一开始选择使用某个中间件比如:RabbitMQ,那么该中间件和系统的耦合性就会非常高。后续如果我们再要替换为 Kafka 那么代码变动会比较大.
  • Spring Cloud Stream解决了开发人员无感知的使用消息中间件的问题,因为Spring Cloud Stream对消息中间件的进一步封装,可以做到代码层面对中间件的无感知,甚至于动态的切换中间件(RabbitMQ 切换为 Kafka),降低系统和中间件的耦合性,让应用程序可以关注更多自己的业务流程。

Spring Cloud Task

文档: https://docs.spring.io/spring-cloud-task/docs/2.4.2/reference/html/

作用:

In most cases, the modern cloud environment is designed around the execution of processes that are not expected to end. If they do end, they are typically restarted. While most platforms do have some way to run a process that is not restarted when it ends, the results of that run are typically not maintained in a consumable way. Spring Cloud Task offers the ability to execute short-lived processes in an environment and record the results. Doing so allows for a microservices architecture around short-lived processes as well as longer running services through the integration of tasks by messages.

译:

在大多数情况下,现代云环境的设计是围绕着执行那些预计不会结束的进程。如果它们确实结束了,它们通常会被重新启动。虽然大多数平台都有一些方法来运行一个结束后不会被重启的进程,但运行的结果通常不会以可消耗的方式来维护。Spring Cloud Task提供了在环境中执行短期进程并记录结果的能力。这样做可以实现围绕短期进程的微服务架构,也可以通过消息整合任务来实现长期运行的服务。

即可以让一个spring cloud项目以会结束的姿态短期执行一个任务, 而不是作为长期存在的进程.

Spring Cloud Vault

文档: https://docs.spring.io/spring-cloud-vault/docs/3.1.0/reference/html/

Spring Cloud Vault Config provides client-side support for externalized configuration in a distributed system. With HashiCorp’s Vault you have a central place to manage external secret properties for applications across all environments. Vault can manage static and dynamic secrets such as username/password for remote applications/resources and provide credentials for external services such as MySQL, PostgreSQL, Apache Cassandra, Couchbase, MongoDB, Consul, AWS and more.

译:

Spring Cloud Vault Config为分布式系统中的外部化配置提供客户端支持。有了HashiCorp的Vault,你就有了一个集中的地方来管理所有环境中的应用程序的外部秘密属性。Vault可以管理静态和动态的机密信息,如远程应用程序/资源的用户名/密码,并为外部服务提供凭证,如MySQL、PostgreSQL、Apache Cassandra、Couchbase、MongoDB、Consul、AWS等。

vault

vault是一个密码/证书集中式管理工具,通过HTTP-API对外提供统一的密码访问入口,并且提供权限控制以及详细的日志审计功能。

一个系统可能需要访问多个带密码的后端:例如数据库、通过API keys对外部系统进行调用,面向服务的架构通信等等。要将众多系统中的用户和权限对应起来已经非常困难,加上提供密钥滚动功能、安全的存储后端还要有详细的审计日志,自定义解决方案几乎不太可能。这也就是vault存在的意义.

Spring Cloud Zookeeper

文档: https://docs.spring.io/spring-cloud-zookeeper/docs/3.1.1/reference/html/#_spring_cloud_zookeeper

This project provides Zookeeper integrations for Spring Boot applications through autoconfiguration and binding to the Spring Environment and other Spring programming model idioms. With a few annotations, you can quickly enable and configure the common patterns inside your application and build large distributed systems with Zookeeper based components. The provided patterns include Service Discovery and Configuration. The project also provides client-side load-balancing via integration with Spring Cloud LoadBalancer.

译:

该项目通过自动配置和与Spring环境及其他Spring编程模型成语的绑定,为Spring Boot应用程序提供Zookeeper集成。通过一些注解,你可以在你的应用程序中快速启用和配置常见的模式,并使用基于Zookeeper的组件构建大型分布式系统。所提供的模式包括服务发现和配置。该项目还通过与Spring Cloud LoadBalancer的集成提供了客户端的负载平衡。

和consul, eureka类似地, spring cloud zookeeper的主要作用也是服务发现,

eureka, consul和zookeeper对cap的支持:

  • C: Consistency(强一致性)
  • A: Availability(可用性)
  • P: Partition tolerance(分区容错)

Eureka因为默认的自我保护机制,可以保证服务节点不会被立即剔除, 保证高并发情况下的可用性, 为AP

consul 和 zookeeper 都是检测到不健康的服务节点立即剔除, 保证了一致性, 为 CP

ref


springcloud简单概要
https://blog.roccoshi.top/posts/12678/
作者
RoccoShi
发布于
2022年5月9日
许可协议