微服务--认识微服务

微服务架构的演变

1. 单体架构(Monolithic)

  • 阶段描述:在单体应用时代,整个应用程序被设计为一个项目,并在一个进程内运行。这种架构方式开发简单,便于集中管理,但随着应用的复杂化,其缺点逐渐显现。
  • 主要特点
    • 开发简单,集中管理。
    • 部署成本低
    • 难以维护,升级困难,无法快捷迭代。

2. 垂直拆分

  • 阶段描述:为了应对单体架构的维护难题,开始出现垂直拆分的做法,即将应用按照功能或业务线拆分为多个独立的部分,每部分独立部署和维护。
  • 主要特点
    • 独立部署和维护,提高了部分灵活性。
    • 但仍可能保持单体模式思维,容易形成重复建设。

3. 分布式服务

  • 阶段描述:随着业务规模的扩大,系统开始采用分布式服务架构,将一系列服务组装成系统,每个服务独立部署、独立运行、独立开发和维护。
  • 主要特点
    • 强调服务的独立性和隔离性。
    • 提高了系统的可扩展性和容错性。

4. 面向服务架构(SOA)

  • 阶段描述:面向服务架构(SOA)是一个组件模型,它将应用程序的不同功能单元(称为服务)进行拆分,并通过定义良好的接口和协议将这些服务联系起来。
  • 主要特点
    • 实现了服务的标准化和可重用性。
    • 提高了系统的灵活性和可维护性。

5. 微服务架构

  • 阶段描述:微服务架构是SOA的进一步发展和细化,它将大型应用程序拆分为一组小型、独立的服务,每个服务都围绕特定的业务功能进行设计、开发、部署和扩展。
  • 主要特点
    • 服务拆分:应用程序被拆分为多个小型服务,每个服务负责一个明确的业务功能。
    • 独立部署:每个服务都可以独立进行部署和升级,不会影响其他服务的正常运行。
    • 分布式通信:服务之间通过轻量级的通信机制进行交互,如RESTful API、消息队列等。
    • 自治性:每个服务都是自治的,可以使用不同的技术栈和数据库,独立进行开发和维护。
    • 可扩展性:可以根据需求独立扩展特定的服务,而不必扩展整个应用程序。
    • 高可用性:一个服务的故障不会影响整个系统的运行,提高了系统的容错性和可用性。
    • 技术多样性:不同的服务可以使用适合自身需求的技术栈,选择最佳的工具和技术。
    • 团队自治:每个服务团队可以独立做出决策和创新,加快开发和部署速度。

6. 云原生微服务架构

  • 阶段描述:随着云原生技术的兴起,如Docker、Kubernetes等,微服务架构得到了更为完善的支撑,形成了云原生微服务架构。
  • 主要特点
    • 强调服务的无状态性和独立性,使得服务更容易在云环境中进行扩展和管理。
    • Kubernetes等容器编排工具成为核心组件,用于容器的编排和管理。
    • Service Mesh(如Istio)等新技术为微服务提供了更为完善的治理功能,如服务发现、负载均衡、故障注入、可观测性和安全等。

认识微服务

微服务(Microservices)是一种软件架构设计模式,它将大型复杂的应用程序拆分成多个小型、自治的服务单元。这些服务单元可以独立部署、扩展和维护,每个服务单元都专注于完成一个特定的业务功能或任务。基于微服务形成的软件架构风格称为微服务架构(Microservices Architecture),它涵盖了使用微服务构建应用程序的全套原则、模式和最佳实践。

SpringCloud

Spring Cloud是一套分布式微服务架构的一站式解决方案,它提供了一套简单易用的编程模型,使我们能在Spring Boot的基础上轻松地实现微服务系统的构建。

  • 定义:Spring Cloud并不是某一门技术,而是一系列微服务解决方案或框架的有序集合。它将市面上成熟的、经过验证的微服务框架整合起来,并通过Spring Boot的思想进行再封装,屏蔽掉其中复杂的配置和实现原理,最终为开发人员提供了一套简单易懂、易部署和易维护的分布式系统开发工具包。
  • 性质:Spring Cloud的中文社区网站有http://springcloud.cn/和Spring Cloud中文网-官方文档中文版等,提供了丰富的资源和文档支持。

拆分与远程调用

一、服务拆分

服务拆分是将一个大的应用程序拆分成多个小的、独立的服务的过程,每个服务专注于解决特定的业务问题。服务拆分的目的是为了提高系统的可维护性、可扩展性和灵活性。

拆分原则

  1. 单一职责原则:每个服务应该只负责一项业务功能,确保服务的职责单一。
  2. 模块化设计:将功能相似的模块放在同一服务中,确保服务内部的模块之间存在高内聚低耦合的关系。
  3. 业务边界划分:根据业务需求划分服务边界,确保服务之间的功能和数据的拆分不会导致业务逻辑混乱或重复。
  4. 垂直拆分:将服务按照业务领域进行垂直拆分,每个服务都有明确的业务范围和职责,这样可以提高系统的可扩展性和维护性。

拆分步骤

  1. 明确服务边界:根据业务功能和需求,明确每个服务的职责和边界。
  2. 划分服务模块:将应用程序中的功能模块按照服务边界进行划分。
  3. 实现服务接口:为每个服务定义清晰的接口,确保服务之间的交互明确和一致。
  4. 部署和运行服务:将每个服务独立部署在不同的服务器或容器中,并确保服务的长时间稳定运行。

二、远程调用

服务提供者(Provider)

服务提供者是一个运行在网络上,能够响应并处理来自服务消费者的请求的应用程序或服务。它通常会对外暴露一个或多个API接口,这些接口定义了可供远程调用的方法。服务提供者负责处理这些方法的逻辑,并返回相应的结果给服务消费者。

服务消费者(Consumer)

服务消费者是一个需要调用远程服务来完成其业务逻辑的应用程序或服务。它不会直接执行所需的业务逻辑,而是通过远程调用的方式,向服务提供者发送请求,并等待响应结果。服务消费者通常使用某种形式的客户端库或框架来发送请求和接收响应,这些库或框架封装了远程调用的底层细节,使得开发者可以更方便地进行远程通信。

远程调用是微服务架构中服务之间通信的重要方式。在Spring Cloud中,远程调用通常通过HTTP REST API、Feign客户端、消息队列等方式实现。

远程调用流程

  1. 服务注册与发现:服务启动后,会向注册中心(如Eureka、Nacos等)注册自己的信息,包括服务地址、端口、元数据等。其他服务通过注册中心可以发现和获取服务信息。
  2. 负载均衡:在调用服务时,通过负载均衡器(如Ribbon、LoadBalancer等)将请求均匀地分发到不同的服务实例上,提高系统的整体性能和稳定性。
  3. 服务调用:客户端通过HTTP REST API、Feign客户端等方式向服务提供者发送请求,服务提供者处理请求并返回结果。
  4. 熔断与降级:为了防止服务调用失败导致整个系统崩溃,可以使用熔断器(如Hystrix、Resilience4j等)进行熔断和降级处理。当服务调用失败或超时达到一定阈值时,熔断器会开启熔断状态,将请求直接返回或执行备用逻辑。

常用组件

  • Feign:Feign是一个声明式的Web服务客户端,它使得编写Web服务客户端变得更加简单。通过创建接口并使用注解来配置它,可以定义服务之间的通信方式。
  • Ribbon:Ribbon是一个客户端负载均衡器,它可以在多个服务实例之间提供智能的负载均衡。
  • Hystrix:Hystrix是一个用于处理分布式系统的延迟和容错的库。它通过隔离服务之间的访问点、停止级联失败和提供回退选项来实现这一点。
  • Nacos:Nacos是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。它提供了服务发现、配置管理、服务管理等关键能力。

Eureka

一、Eureka的组成

Eureka架构主要包括Eureka Server(服务端,注册中心)和Eureka Client(客户端)两大部分。

  1. Eureka Server
    • 作用:作为服务注册中心,负责维护服务实例的注册信息,并提供服务实例的查询功能。暂存地址 调用时给服务块发送地址
    • 功能
      • 服务注册:服务实例启动时,会向Eureka Server注册自己的信息,包括服务名、IP地址、端口号等。
      • 服务续租:服务实例定期(默认30秒)向Eureka Server发送心跳,以续租其租约,表明自己仍然可用。
      • 服务注销:服务实例关闭时,会向Eureka Server发送注销请求,Eureka Server将此实例从注册列表中移除。
      • 服务列表获取:服务消费者从Eureka Server获取服务列表,并根据负载均衡策略选择一个服务实例进行调用。
  2. Eureka Client
    • 分类:Eureka Client分为服务提供者(Provider)和服务消费者(Consumer)两类。
    • 服务提供者
      • 在启动时向Eureka Server注册自己的信息。
      • 每隔一定时间(默认30秒)向Eureka Server发送心跳,以维持其租约。
    • 服务消费者
      • 通过Eureka Server查找可用的服务实例。
      • 从Eureka Server获取服务列表,并根据负载均衡策略选择一个服务实例进行调用。

二、Eureka的特性

  1. 高可用:Eureka Server支持集群部署,多个Eureka Server实例相互注册,形成高可用的服务注册中心。
  2. 容错性:Eureka Client在与Eureka Server进行通信时,如果某个Eureka Server宕机,Eureka Client会自动切换到其他Eureka Server进行通信。
  3. 负载均衡:Eureka与Ribbon等客户端负载均衡器结合使用,可以实现服务的负载均衡。
  4. 健康检查:Eureka Server通过心跳机制来检查服务实例的健康状态,如果服务实例在预定时间内未发送心跳,Eureka Server会将其标记为不健康或已下线。

三、Eureka的应用场景

Eureka适用于微服务架构中的服务注册与发现场景。在微服务架构中,服务实例数量众多,且经常需要动态地添加或删除服务实例。Eureka通过提供注册中心的功能,使得服务实例能够动态地注册和注销,同时服务消费者也能够通过Eureka Server方便地获取服务列表并进行服务调用。

四、Eureka的使用

在使用Eureka时,通常需要搭建Eureka Server,并在服务提供者和服务消费者中引入Eureka Client依赖。服务提供者在启动时会自动向Eureka Server注册自己的信息,服务消费者则通过Eureka Server获取服务列表并进行服务调用。

五、Eureka的故障处理

Eureka提供了多种故障处理机制,以确保系统的稳定性和可用性。例如,当服务实例出现故障时,Eureka Server会将其从注册列表中移除,避免其他服务消费者继续调用该故障实例。同时,服务消费者可以通过实施重试机制、启用熔断机制等方式来应对服务故障。

Eureka Server(注册中心)

<!--XML-->
<dependencies>  <dependency>  <groupId>org.springframework.cloud</groupId>  <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>  </dependency>  <!-- 添加Spring Boot启动器依赖 -->  <dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-web</artifactId>  </dependency>  <!-- 其他依赖 -->  
</dependencies>  <dependencyManagement>  <dependencies>  <dependency>  <groupId>org.springframework.cloud</groupId>  <artifactId>spring-cloud-dependencies</artifactId>  <version>Your-Spring-Cloud-Version</version> <!-- 替换为你的Spring Cloud版本 -->  <type>pom</type>  <scope>import</scope>  </dependency>  </dependencies>  
</dependencyManagement>
//启动类上添加@EnableEurekaServer注解:
import org.springframework.boot.SpringApplication;  
import org.springframework.boot.autoconfigure.SpringBootApplication;  
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;  @SpringBootApplication  
@EnableEurekaServer  
public class EurekaServerApplication {  public static void main(String[] args) {  SpringApplication.run(EurekaServerApplication.class, args);  }  
}
########application.yml配置:##########
server:  port: 8761  eureka:  client:  register-with-eureka: false  fetch-registry: false  server:  wait-time-in-ms-when-sync-empty: 0

Eureka Client(服务注册)

<!--pom.xml-->
<dependencies>  <dependency>  <groupId>org.springframework.cloud</groupId>  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>  </dependency>  <!-- 添加你的服务所需的依赖,比如web starter -->  <dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-web</artifactId>  </dependency>  <!-- 其他依赖 -->  
</dependencies>  <dependencyManagement>  <!-- 与Eureka Server相同 -->  
</dependencyManagement>
import org.springframework.boot.SpringApplication;  
import org.springframework.boot.autoconfigure.SpringBootApplication;  
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;  @SpringBootApplication  
@EnableDiscoveryClient  
public class ServiceApplication {  public static void main(String[] args) {  SpringApplication.run(ServiceApplication.class, args);  }  
}
server:  port: 8080  spring:  application:  name: my-service  eureka:  client:  serviceUrl:  defaultZone: http://localhost:8761/eureka/  instance:  hostname: localhost  prefer-ip-address: true

Ribbon

Ribbon是Spring Cloud生态系统中一个用于客户端的负载均衡器,它基于Netflix Ribbon实现。Ribbon的主要功能是在微服务架构中,通过提供一系列的负载均衡策略,将客户端的请求智能地分发到后端服务的多个实例上,从而提高系统的可用性和扩展性。

Ribbon的核心功能

  1. 负载均衡
    • Ribbon可以将用户请求根据一定的策略(如轮询、随机等)分发到后端服务的多个实例上,以达到负载均衡的效果。
    • 它支持多种负载均衡策略,允许用户根据实际需求进行选择和配置。
  2. 服务调用
    • 在微服务架构中,Ribbon通常与RestTemplate等客户端工具一起使用,方便地进行服务间的调用。
    • 通过在RestTemplate上添加@LoadBalanced注解,可以轻松地实现服务的负载均衡调用。

创建一个配置类来显式地设置IRule Bean:

@Bean  
public IRule customRule() {  
return new CustomRule();  
}  

通过在application.ymlapplication.properties文件中设置属性

myclient:  ribbon:  NFLoadBalancerRuleClassName: com.example.CustomRule

​​​​​​Ribbon的负载均衡策略

Ribbon支持多种负载均衡策略,常见的包括:

  1. 轮询(RoundRobinRule)
    • 默认策略,按顺序依次选择服务实例进行调用。
  2. 随机(RandomRule)
    • 随机选择一个服务实例进行调用,这种策略可以确保请求尽量均匀地分布到各个服务实例上。
  3. 权重分配(WeightedResponseTimeRule)
    • 根据服务实例的响应时间等性能指标动态调整权重,优先调用权重较高的服务实例。
  4. 最少活跃调用数(BestAvailableRule)
    • 选择当前活跃调用数最少的服务实例进行调用,以减少等待时间。
  5. 一致性哈希(ConsistentHashRule)
    • 通过一致性哈希算法选择服务实例,这种策略可以保证相同请求在一段时间内总是被转发到同一个服务实例上,适用于需要会话保持的场景。
  6. 饥饿加载

        饥饿加载(Eager Loading)是软件开发中常用的一种加载数据或资源的策略,其主要特点是在需要之前就预先加载所有可能需要的数据或资源。以下是对饥饿加载的详细解析:

  • 定义与特点

  • 定义:饥饿加载指的是在应用程序启动或对象初始化阶段,就加载所有可能需要使用的数据,无论这些数据在实际运行中是否会被用到。
  • 特点
    1. 预加载:在需要之前就完成数据的加载,确保数据在首次访问时能够快速响应。
    2. 减少延迟:由于数据已经预先加载到内存中,因此在首次访问时可以避免加载数据导致的延迟。
    3. 内存消耗:可能会浪费内存资源,因为预先加载了大量数据,其中一部分可能并未被实际使用。
    4. 启动时间:对于大型数据集或复杂对象图,饥饿加载可能导致应用程序的启动时间延长。

Ribbon的工作原理

  1. 服务发现
    • Ribbon通常与Eureka等服务注册与发现中心配合使用。服务实例在启动时将自己注册到Eureka Server上,Ribbon客户端从Eureka Server获取服务实例的注册信息。
  2. 负载均衡
    • Ribbon客户端在获取到服务实例的注册信息后,根据配置的负载均衡策略选择一个服务实例进行调用。
  3. 请求转发
    • 将客户端的请求转发到选中的服务实例上,并处理响应结果。

Ribbon的配置

Ribbon的配置可以通过配置文件或代码的方式进行:

  • 配置文件方式:在application.yml或application.properties中配置Ribbon的相关属性,如负载均衡策略等。
  • 代码方式:在微服务的启动类中通过编写配置类来定义Ribbon的Bean,并设置相应的负载均衡策略。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【算法 动态规划 简单多状态 dp 问题】打家劫舍题型

打家劫舍题型 按摩师 (easy)解题思路代码 打家劫舍II &#xff08;medium&#xff09;解题思路代码 删除并获得点数&#xff08;medium&#xff09;解题思路代码 按摩师 (easy) 题目链接 该题是打家劫舍的变形 解题思路 状态表示 分析: 注意题目, 对于当天的预约, 可以接受…

C语言遇见的一些小问题

问题如下&#xff1a; 1&#xff1a;为什么这样的代码为报错 #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <algorithm> #include <cstdio> #include<string> #include<stdlib.h> using namespace std; int main() {int i …

mysql5.7 TIMESTAMP NOT NULL DEFAULT ‘0000-00-00 00:00:00‘ 换版8版本 引发的问题

mysql5.7 TIMESTAMP NOT NULL DEFAULT 0000-00-00 00:00:00 换版引发的问题 问题背景sql_mode上机演示5.78.4 问题背景 在项目mysql版本由5.7 换版到8.4版本后&#xff0c;我们进行回归测试时&#xff0c;却发现一个积年代码报错了&#xff0c;是数据库插入报的错 xxx can not…

华为IS-IS实验及配置

AR1配置 #进入ISIS进程 isis 1 #配置设备类型为Level-1is-level level-1 #定义区域和System-ID等信息network-entity 49.0001.0010.0000.0001.00 #ISIS邻居命名is-name AR1 #接口配置IP和启用ISIS interface GigabitEthernet0/0/0ip address 10.1.12.1 255.255.255.0 isis ena…

数仓基础(六):离线与实时数仓区别和建设思路

文章目录 离线与实时数仓区别和建设思路 一、离线数仓与实时数仓区别 二、实时数仓建设思路 离线与实时数仓区别和建设思路 ​​​​​​​一、离线数仓与实时数仓区别 离线数据与实时数仓区别如下&#xff1a; 对比方面 离线数仓 实时数仓 架构选择 传统大数据架构 …

Ribbon负载均衡底层原理

springcloude服务实例与服务实例之间发送请求&#xff0c;首先根据服务名注册到nacos&#xff0c;然后发送请求&#xff0c;nacos可以根据服务名找到对应的服务实例。 SpringCloudRibbon的底层采用了一个拦截器&#xff0c;拦截了openfeign发出的请求&#xff0c;对地址做了修…

【C++】将myString类中能够实现的操作都实现一遍

myString.h #ifndef MYSTERAM_H #define MYSTERAM_H #include <iostream> #include<cstring> using namespace std; class myString { private:char *str; //字符串int size; //字符串容量char error[20] "error"; public://无参构造myString():siz…

深入解析FPGA在SOC设计中的核心作用

在集成系统SoC设计中&#xff0c;CPU核心的嵌入至关重要&#xff0c;以实现软硬件的有效交互。此过程中涉及到功能IP&#xff08;如图像处理、无线通信等&#xff09;的验证和整合&#xff0c;利用硬件描述语言(HDL)来实现可编程逻辑(FPGA)&#xff0c;并通过验证技术提高设计效…

Django Admin对自定义的计算字段进行排序

通常&#xff0c;Django会为模型属性字段&#xff0c;自动添加排序功能。当你添加计算字段时&#xff0c;Django不知道如何执行order_by&#xff0c;因此它不会在该字段上添加排序功能。 如果要在计算字段上添加排序&#xff0c;则必须告诉Django需要排序的内容。你可以通过在…

【机器学习】神经网络、隐藏层的基本概念、如何选择隐藏层数量以及胶囊网络对神经网络的影响

引言 神经网络是机器学习的一种方法&#xff0c;它通过模拟人脑神经元的工作原理来构建算法 文章目录 引言一、神经网络1.1 定义1.2 主要组成部分1.3 工作原理1.4 应用1.5 类型1.6 优化算法1.7 总结 二、隐藏层2.1 定义2.2 隐藏层的作用2.3 隐藏层的数量和大小2.4 隐藏层的结构…

单片机-STM32 时钟(六)

1.时钟的概念 在我们单片机中&#xff0c;时钟主要是用于 提供一个工作的频率&#xff0c;时钟信号越大&#xff0c;设备执行的速度就越快。 时钟---处理器运行的频率---72MHZ Dbus--数据总线 AHB--总线桥 APB2--外设总线2&#xff08;时钟&#xff09; APB1--外设总线1&a…

基于Java+SpringBoot+Vue的植物健康系统

基于JavaSpringBootVue的植物健康系统 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345; 某信 gzh 搜索【智能编程小助手】获取项…

[C++11#44](一) 统一的列表初始化 | 声明 | STL中一些变化 | emplace的优化 | move

目录 0. 回忆 1.隐式类型转化 特性 1.统一的列表初始化 1.{}初始化 2.2 std::initializer_list 二、声明 1.auto 2.decltype 3.nullptr 宏定义的例子 使用 const 和 enum 替代宏 4. 范围 for 循环 5.final与override final 关键字 override 关键字 示例代码 智…

wpf prism 《3》 弹窗 IOC

传统的弹窗 这种耦合度高 new 窗体() . Show(); new 窗体() . ShowDialog(); 利用Prism 自动的 IOC 弹窗的 必须 必须 必须 页面控件 弹窗的 必须 必须 必须 页面控件 弹窗的 必须 必须 必须 页面控件 弹窗的 必须 必须 必须 页面控件 弹窗的 必须 必须 必须 页面控件 》》否…

惠中科技光伏清洗剂:绿色清洁,引领光伏行业新潮流

在当今全球能源转型的大潮中&#xff0c;光伏产业作为绿色能源的重要组成部分&#xff0c;正以前所未有的速度蓬勃发展。然而&#xff0c;随着光伏板在户外环境的长时间暴露&#xff0c;其表面不可避免地会积累灰尘、鸟粪、油污等污染物&#xff0c;严重影响光伏板的透光率和发…

tiny_qemu模拟qemu虚拟化原理

一、模仿一个x86平台虚机 cpu虚拟化原理来源于Linux虚拟化KVM-Qemu分析&#xff08;四&#xff09;之CPU虚拟化&#xff08;2&#xff09; 笔者就实现了下相关操作。看汇编是在x86平台下操作的&#xff0c;其中两个文件分别是 1.tiny_kernel.S start: /* Hello */ mov …

数据安全与个人信息保护的辨析

文章目录 前言一、合规1、合规的目标导向原则2、监管平衡的原则二、基础设施1、公共基础设施2、企业基础设施三、数据流通1、数据生产要素是数字化时代生产要素的变革理论2、数据产品的保护源自于数据产品的价值四、产品与服务1、数据安全与网络安全2、数据安全的分类分级与数据…

Unity(2022.3.41LTS) - UI详细介绍-Scrollbar(滚动条)

目录 零.简介 一、基本功能与用途 二、组件介绍 三、使用方法 四、优化和注意事项 五.和滑动条的区别 零.简介 在 Unity 中&#xff0c;滚动条&#xff08;Scrollbar&#xff09;是一种用于实现滚动功能的 UI 组件。 一、基本功能与用途 滚动内容&#xff1a;主要用于…

NeRF原理学习

一个2020年的工作我现在才来学习并总结它的原理&#xff0c;颇有种“时过境迁”的感觉。这篇总结是基于NeRF原文 NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis 阅读理解后写的&#xff0c;作用是以后如果记不太清了可以回忆。 目的&应用 先说…

Java项目:128 基于Spring Boot的装饰工程管理系统

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 本系统包含管理员、员工和客户角色 管理员权限操作的功能包括管理合同信息&#xff0c;管理合同报价&#xff0c;管理立项项目&#xff0c;管…