当前位置: 首页 > news >正文

K8s(健康检查+滚动更新+优雅停机+弹性伸缩+Prometheus监控+配置分离)

前言

快速配置请直接跳转至汇总配置

K8s + SpringBoot实现零宕机发布:健康检查+滚动更新+优雅停机+弹性伸缩+Prometheus监控+配置分离(镜像复用)
配置
健康检查

健康检查类型:就绪探针(readiness)+ 存活探针(liveness)探针类型:exec(进入容器执行脚本)、tcpSocket(探测端口)、httpGet(调用接口)

业务层面

项目依赖 pom.xml
 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency>

定义访问端口、路径及权限 application.yaml

management:server:port: 50000                         # 启用独立运维端口endpoint:                             # 开启health端点health:probes:enabled: trueendpoints:web:exposure:base-path: /actuator            # 指定上下文路径,启用相应端点include: health

将暴露/actuator/health/readiness和/actuator/health/liveness两个接口,访问方式如下:

http://127.0.0.1:50000/actuator/health/readiness
http://127.0.0.1:50000/actuator/health/liveness

运维层面

k8s部署模版deployment.yaml
apiVersion: apps/v1
kind: Deployment
spec:template:spec:containers:- name: {APP_NAME}image: {IMAGE_URL}imagePullPolicy: Alwaysports:- containerPort: {APP_PORT}- name: management-portcontainerPort: 50000         # 应用管理端口readinessProbe:                # 就绪探针httpGet:path: /actuator/health/readinessport: management-portinitialDelaySeconds: 30      # 延迟加载时间periodSeconds: 10            # 重试时间间隔timeoutSeconds: 1            # 超时时间设置successThreshold: 1          # 健康阈值failureThreshold: 6          # 不健康阈值livenessProbe:                 # 存活探针httpGet:path: /actuator/health/livenessport: management-portinitialDelaySeconds: 30      # 延迟加载时间periodSeconds: 10            # 重试时间间隔timeoutSeconds: 1            # 超时时间设置successThreshold: 1          # 健康阈值failureThreshold: 6          # 不健康阈值

滚动更新

k8s资源调度之滚动更新策略,若要实现零宕机发布,需支持健康检查

apiVersion: apps/v1
kind: Deployment
metadata:name: {APP_NAME}labels:app: {APP_NAME}
spec:selector:matchLabels:app: {APP_NAME}replicas: {REPLICAS}				# Pod副本数strategy:type: RollingUpdate				# 滚动更新策略rollingUpdate:maxSurge: 1                   # 升级过程中最多可以比原先设置的副本数多出的数量maxUnavailable: 1             # 升级过程中最多有多少个POD处于无法提供服务的状态

优雅停机

在K8s中,当我们实现滚动升级之前,务必要实现应用级别的优雅停机。否则滚动升级时,还是会影响到业务。使应用关闭线程、释放连接资源后再停止服务
业务层面

项目依赖 pom.xml
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

定义访问端口、路径及权限 application.yaml

spring:application:name: <xxx>profiles:active: @profileActive@lifecycle:timeout-per-shutdown-phase: 30s     # 停机过程超时时长设置30s,超过30s,直接停机server:port: 8080shutdown: graceful                    # 默认为IMMEDIATE,表示立即关机;GRACEFUL表示优雅关机management:server:port: 50000                         # 启用独立运维端口endpoint:                             # 开启shutdown和health端点shutdown:enabled: truehealth:probes:enabled: trueendpoints:web:exposure:base-path: /actuator            # 指定上下文路径,启用相应端点include: health,shutdown

将暴露/actuator/shutdown接口,调用方式如下:

curl -X POST 127.0.0.1:50000/actuator/shutdown

运维层面

确保dockerfile模版集成curl工具,否则无法使用curl命令

FROM openjdk:8-jdk-alpine
#构建参数
ARG JAR_FILE
ARG WORK_PATH="/app"
ARG EXPOSE_PORT=8080#环境变量
ENV JAVA_OPTS=""\JAR_FILE=${JAR_FILE}#设置时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories  \&& apk add --no-cache curl
#将maven目录的jar包拷贝到docker中,并命名为for_docker.jar
COPY target/$JAR_FILE $WORK_PATH/#设置工作目录
WORKDIR $WORK_PATH

指定于外界交互的端口

EXPOSE $EXPOSE_PORT

配置容器,使其可执行化

ENTRYPOINT exec java $JAVA_OPTS -jar $JAR_FILE

k8s部署模版deployment.yaml

注:经验证,java项目可省略结束回调钩子的配置

此外,若需使用回调钩子,需保证镜像中包含curl工具,且需注意应用管理端口(50000)不能暴露到公网

apiVersion: apps/v1
kind: Deployment
spec:template:spec:containers:- name: {APP_NAME}image: {IMAGE_URL}imagePullPolicy: Alwaysports:- containerPort: {APP_PORT}- containerPort: 50000lifecycle:preStop: 						# 结束回调钩子exec:command: ["curl", "-XPOST", "127.0.0.1:50000/actuator/shutdown"]

弹性伸缩

为pod设置资源限制后,创建HPA

apiVersion: apps/v1
kind: Deployment
metadata:name: {APP_NAME}labels:app: {APP_NAME}
spec:template:spec:containers:- name: {APP_NAME}image: {IMAGE_URL}imagePullPolicy: Alwaysresources:                     # 容器资源管理limits:                      # 资源限制(监控使用情况)cpu: 0.5memory: 1Girequests:                    # 最小可用资源(灵活调度)cpu: 0.15memory: 300Mi
kind: HorizontalPodAutoscaler            # 弹性伸缩控制器
apiVersion: autoscaling/v2beta2
metadata:name: {APP_NAME}
spec:scaleTargetRef:apiVersion: apps/v1kind: Deploymentname: {APP_NAME}minReplicas: {REPLICAS}                # 缩放范围maxReplicas: 6metrics:- type: Resourceresource:name: cpu                        # 指定资源指标target:type: UtilizationaverageUtilization: 50

Prometheus集成
业务层面

项目依赖 pom.xml<!-- 引入Spring boot的监控机制-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency><groupId>io.micrometer</groupId><artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

定义访问端口、路径及权限 application.yaml

management:server:port: 50000                         # 启用独立运维端口metrics:tags:application: ${spring.application.name}endpoints:web:exposure:base-path: /actuator            # 指定上下文路径,启

用相应端点
include: metrics,prometheus

将暴露/actuator/metric和/actuator/prometheus接口,访问方式如下:

http://127.0.0.1:50000/actuator/metric
http://127.0.0.1:50000/actuator/prometheus

运维层面 deployment.yaml

apiVersion: apps/v1
kind: Deployment
spec:template:metadata:annotations:prometheus:io/port: "50000"prometheus.io/path: /actuator/prometheus  # 在流水线中赋值prometheus.io/scrape: "true"              # 基于pod的服务发现

配置分离

方案:通过configmap挂载外部配置文件,并指定激活环境运行

作用:配置分离,避免敏感信息泄露;镜像复用,提高交付效率

通过文件生成configmap

通过dry-run的方式生成yaml文件

kubectl create cm -n <APP_NAME> --from-file=application-test.yaml --dry-run=1 -oyaml > configmap.yaml

更新

kubectl apply -f configmap.yaml

挂载configmap并指定激活环境

apiVersion: apps/v1
kind: Deployment
metadata:name: {APP_NAME}labels:app: {APP_NAME}
spec:template:spec:containers:- name: {APP_NAME}image: {IMAGE_URL}imagePullPolicy: Alwaysenv:- name: SPRING_PROFILES_ACTIVE   # 指定激活环境value: testvolumeMounts:                      # 挂载configmap- name: confmountPath: "/app/config"         # 与Dockerfile中工作目录一致readOnly: truevolumes:- name: confconfigMap:name: {APP_NAME}

汇总配置

业务层面

项目依赖 pom.xml<!-- 引入Spring boot的监控机制-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency><groupId>io.micrometer</groupId><artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

定义访问端口、路径及权限 application.yaml

spring:application:name: project-sampleprofiles:active: @profileActive@lifecycle:timeout-per-shutdown-phase: 30s     # 停机过程超时时长设置30s,超过30s,直接停机server:port: 8080shutdown: graceful                    # 默认为IMMEDIATE,表示立即关机;GRACEFUL表示优雅关机management:server:port: 50000                         # 启用独立运维端口metrics:tags:application: ${spring.application.name}endpoint:                             # 开启shutdown和health端点shutdown:enabled: truehealth:probes:enabled: trueendpoints:web:exposure:base-path: /actuator            # 指定上下文路径,启用相应端点include: health,shutdown,metrics,prometheus

运维层面

确保dockerfile模版集成curl工具,否则无法使用curl命令

FROM openjdk:8-jdk-alpine
#构建参数
ARG JAR_FILE
ARG WORK_PATH="/app"
ARG EXPOSE_PORT=8080#环境变量
ENV JAVA_OPTS=""\JAR_FILE=${JAR_FILE}#设置时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories  \&& apk add --no-cache curl
#将maven目录的jar包拷贝到docker中,并命名为for_docker.jar
COPY target/$JAR_FILE $WORK_PATH/#设置工作目录
WORKDIR $WORK_PATH# 指定于外界交互的端口
EXPOSE $EXPOSE_PORT
# 配置容器,使其可执行化
ENTRYPOINT exec java $JAVA_OPTS -jar $JAR_FILE

k8s部署模版deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:name: {APP_NAME}labels:app: {APP_NAME}
spec:selector:matchLabels:app: {APP_NAME}replicas: {REPLICAS}                            # Pod副本数strategy:type: RollingUpdate                           # 滚动更新策略rollingUpdate:maxSurge: 1maxUnavailable: 0template:metadata:name: {APP_NAME}labels:app: {APP_NAME}annotations:timestamp: {TIMESTAMP}prometheus.io/port: "50000"               # 不能动态赋值prometheus.io/path: /actuator/prometheusprometheus.io/scrape: "true"              # 基于pod的服务发现spec:affinity:                                   # 设置调度策略,采取多主机/多可用区部署podAntiAffinity:preferredDuringSchedulingIgnoredDuringExecution:- weight: 100podAffinityTerm:labelSelector:matchExpressions:- key: appoperator: Invalues:- {APP_NAME}topologyKey: "kubernetes.io/hostname" # 多可用区为"topology.kubernetes.io/zone"terminationGracePeriodSeconds: 30             # 优雅终止宽限期containers:- name: {APP_NAME}image: {IMAGE_URL}imagePullPolicy: Alwaysports:- containerPort: {APP_PORT}- name: management-portcontainerPort: 50000         # 应用管理端口readinessProbe:                # 就绪探针httpGet:path: /actuator/health/readinessport: management-portinitialDelaySeconds: 30      # 延迟加载时间periodSeconds: 10            # 重试时间间隔timeoutSeconds: 1            # 超时时间设置successThreshold: 1          # 健康阈值failureThreshold: 9          # 不健康阈值livenessProbe:                 # 存活探针httpGet:path: /actuator/health/livenessport: management-portinitialDelaySeconds: 30      # 延迟加载时间periodSeconds: 10            # 重试时间间隔timeoutSeconds: 1            # 超时时间设置successThreshold: 1          # 健康阈值failureThreshold: 6          # 不健康阈值resources:                     # 容器资源管理limits:                      # 资源限制(监控使用情况)cpu: 0.5memory: 1Girequests:                    # 最小可用资源(灵活调度)cpu: 0.1memory: 200Mienv:- name: TZvalue: Asia/Shanghai
---
kind: HorizontalPodAutoscaler            # 弹性伸缩控制器
apiVersion: autoscaling/v2beta2
metadata:name: {APP_NAME}
spec:scaleTargetRef:apiVersion: apps/v1kind: Deploymentname: {APP_NAME}minReplicas: {REPLICAS}                # 缩放范围maxReplicas: 6metrics:- type: Resourceresource:name: cpu                        # 指定资源指标target:type: UtilizationaverageUtilization: 50

相关文章:

K8s(健康检查+滚动更新+优雅停机+弹性伸缩+Prometheus监控+配置分离)

前言 快速配置请直接跳转至汇总配置 K8s SpringBoot实现零宕机发布&#xff1a;健康检查滚动更新优雅停机弹性伸缩Prometheus监控配置分离&#xff08;镜像复用&#xff09; 配置 健康检查 健康检查类型&#xff1a;就绪探针&#xff08;readiness&#xff09; 存活探针&am…...

Django学习记录:使用ORM操作MySQL数据库并完成数据的增删改查

Django学习记录&#xff1a;使用ORM操作MySQL数据库并完成数据的增删改查 数据库操作 MySQL数据库pymysql Django开发操作数据库更简单&#xff0c;内部提供了ORM框架。 安装第三方模块 pip install mysqlclientORM可以做的事&#xff1a; 1、创建、修改、删除数据库中的…...

React Hooks 中的 useEffect(副作用)

useEffect 是什么&#xff1f; useEffect 是一个 React Hook&#xff0c;它允许你将组件与外部系统同步 当我们在 React 中使用 useEffect 这个 Hook 时&#xff0c;实际上是在告诉 React 在特定情况下执行我们定义的副作用函数。这种副作用函数可以处理一些与组件渲染结果无关…...

[CKA]考试之持久化存储卷PersistentVolume

由于最新的CKA考试改版&#xff0c;不允许存储书签&#xff0c;本博客致力怎么一步步从官网把答案找到&#xff0c;如何修改把题做对&#xff0c;下面开始我们的 CKA之旅 题目为&#xff1a; Task 创建一个pv&#xff0c;名字为app-config&#xff0c;大小为2Gi&#xff0c;…...

基于LLM的SQL应用程序开发实战(一)

基于LLM的SQL应用程序开发实战(一) 16.1 SQL on LLMs应用程序初始化 本节主要从案例代码的角度切入,探索ChatGPT以及大模型,尤其是从生产环境的视角,来思考具体的最佳实践。本节主要跟大家谈的是,在LangChain这样一个框架下,我们使用GPT-3.5或者GPT-4大模型,同时使用第…...

如何批量实现多行合并后居中

思路&#xff1a; 1.先填充数据 2.数据分类统计制作格式 3.格式刷刷制作出的格式 1.填充数据 思路&#xff1a;选中&#xff0c;F5定位空值&#xff0c;&#xff0c;⬆&#xff08;键盘上的上下左右哪里的上键&#xff09;&#xff0c;按住Ctrl然后按Enter。 2.数据分类统计…...

【深度学习_TensorFlow】手写数字识别

写在前面 到这里为止&#xff0c;我们已经学习完张量的常用操作方法&#xff0c;已具备实现大部分神经网络技术的基础储备了。这一章节我们将开启神经网络的学习&#xff0c;然而并不需要像学习前面那样了解大量的张量操作&#xff0c;而是将重点转向理解概念知识&#xff0c;…...

antv/l7地图,鼠标滚动,页面正常滑动-- 我们忽略的deltaY

背景 在官网项目中&#xff0c;需要使用一个地图&#xff0c;展示产品的分布区域及数量。希望的交互是&#xff0c;鼠标放上标点&#xff0c;tooltip展示地点和数量等信息。鼠标滚动&#xff0c;则页面随着滚动。但是鼠标事件是被地图代理了的&#xff0c;鼠标滚动意味着地图的…...

再续AM335x经典,米尔TI AM62x核心板上市,赋能新一代HMI

近十年来&#xff0c;AM335x芯片作为TI经典工业MPU产品&#xff0c;在工业处理器市场占据主流地位&#xff0c;其凭借GPMC高速并口、PRU协处理器等个性化硬件资源&#xff0c;在工业控制、能源电力、轨道交通、智慧医疗等领域广受用户欢迎。随着信息技术的快速发展&#xff0c;…...

springboot和Django哪一个做web服务器框架更好

目录 一、两者特点 二、各自优势 一、两者特点 编程语言&#xff1a; Spring Boot&#xff1a;使用 Java 编程语言。Django&#xff1a;使用 Python 编程语言。 生态系统和社区支持&#xff1a; Spring Boot&#xff1a;具有庞大的 Java 生态系统和强大的社区支持。适用于大型…...

C#核心知识回顾——21.归并排序

理解递归逻辑 一开始不会执行sort函数的 要先找到最小容量数组时 才会回头递归调用Sort进行排序 基本原理 归并 递归 合并 数组分左右 左右元素相比较 一侧用完放对面 不停放入新数组 递归不停分 分…...

基于netty的rpc远程调用

QPRC &#x1f680;&#x1f680;&#x1f680;这是一个手写RPC项目&#xff0c;用于实现远程过程调用&#xff08;RPC&#xff09;通信&#x1f680;&#x1f680;&#x1f680; 欢迎star串门&#xff1a;https://github.com/red-velet/ &#x1f680;Q-PRC 一、功能特性 …...

RabbitMQ输出日志配置

参考地址rabbitmq启用日志功能记录消息队列收发情况_rabbitmq开启日志_普通网友的博客-CSDN博客 启用日志插件命令 # 设置用户权限 rabbitmqctl set_user_tags mqtt-user administrator rabbitmqctl set_permissions -p / mqtt-user ".*" ".*" ".*&…...

解决一个Sqoop抽数慢的问题,yarn的ATSv2嵌入式HBASE崩溃引起

新搭建的一个Hadoop环境&#xff0c;用Sqoop批量抽数的时候发现特别慢&#xff0c;我们正常情况下是一个表一分钟左右&#xff0c;批量抽十几个表&#xff0c;也就是10分钟的样子&#xff0c;结果发现用了2个小时&#xff1a; 查看yarn日志 发现有如下情况&#xff1a; 主要有两…...

为Android构建现代应用——应用导航设计

在前一章节的实现中&#xff0c;Skeleton: Main structure&#xff0c;我们留下了几个 Jetpack 架构组件&#xff0c;这些组件将在本章中使用&#xff0c;例如 Composables、ViewModels、Navigation 和 Hilt。此外&#xff0c;我们还通过 Scaffold 集成了 TopAppBar 和 BottomA…...

聊聊 Docker 和 Dockerfile

目录 一、前言 二、了解Dockerfile 三、Dockerfile 指令 四、多阶段构建 五、Dockerfile 高级用法 六、小结 一、前言 对于开发人员来说&#xff0c;会Docker而不知道Dockerfile等于不会Docker&#xff0c;上一篇文章带大家学习了Docker的基本使用方法&#xff1a;《一文…...

element表格+表单+表单验证结合u

一、结果展示 1、图片 2、描述 table中放form表单&#xff0c;放输入框或下拉框或多选框等&#xff1b; 点击添加按钮&#xff0c;首先验证表单&#xff0c;如果存在没填的就验证提醒&#xff0c;都填了就向下添加一行表单表格&#xff1b; 点击当前行删除按钮&#xff0c;…...

数据库:MYSQL参数max_allowed_packet 介绍

1、参数作用 max_allowed_packet参数是指mysql服务器端和客户端在一次传送数据包的过程当中最大允许的数据包大小。如果超过了设置的最大长度,则会数据库保持数据失败。 2、问题场景 ● 有时候业务的需要,可能会存在某些字段数据长度非常大(比如富文本编辑器里面的内容),…...

基于DiscordMidjourney API接口实现文生图

https://discord.com/api/v9/interactions 请求头&#xff1a; authorization:取自 浏览器中discord 文生图请求头中的 authorization 的值 Content-Type:application/json 请求体&#xff1a; {“type”:2,“application_id”:“93692956130267xxxx”,“guild_id”:“1135900…...

springboot+vue农产品特产商城销售平台_50kf2 多商家

随着我国经济的高速发展与人们生活水平的日益提高&#xff0c;人们对生活质量的追求也多种多样。尤其在人们生活节奏不断加快的当下&#xff0c;人们更趋向于足不出户解决生活上的问题&#xff0c;南阳特产销售平台展现了其蓬勃生命力和广阔的前景。与此同时&#xff0c;为解决…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

Linux部署私有文件管理系统MinIO

最近需要用到一个文件管理服务&#xff0c;但是又不想花钱&#xff0c;所以就想着自己搭建一个&#xff0c;刚好我们用的一个开源框架已经集成了MinIO&#xff0c;所以就选了这个 我这边对文件服务性能要求不是太高&#xff0c;单机版就可以 安装非常简单&#xff0c;几个命令就…...

MySQL的pymysql操作

本章是MySQL的最后一章&#xff0c;MySQL到此完结&#xff0c;下一站Hadoop&#xff01;&#xff01;&#xff01; 这章很简单&#xff0c;完整代码在最后&#xff0c;详细讲解之前python课程里面也有&#xff0c;感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...

Qt的学习(一)

1.什么是Qt Qt特指用来进行桌面应用开发&#xff08;电脑上写的程序&#xff09;涉及到的一套技术Qt无法开发网页前端&#xff0c;也不能开发移动应用。 客户端开发的重要任务&#xff1a;编写和用户交互的界面。一般来说和用户交互的界面&#xff0c;有两种典型风格&…...

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...

Yii2项目自动向GitLab上报Bug

Yii2 项目自动上报Bug 原理 yii2在程序报错时, 会执行指定action, 通过重写ErrorAction, 实现Bug自动提交至GitLab的issue 步骤 配置SiteController中的actions方法 public function actions(){return [error > [class > app\helpers\web\ErrorAction,],];}重写Error…...

工厂方法模式和抽象工厂方法模式的battle

1.案例直接上手 在这个案例里面&#xff0c;我们会实现这个普通的工厂方法&#xff0c;并且对比这个普通工厂方法和我们直接创建对象的差别在哪里&#xff0c;为什么需要一个工厂&#xff1a; 下面的这个是我们的这个案例里面涉及到的接口和对应的实现类&#xff1a; 两个发…...