使用Spring Boot和Spring Cloud实现多租户架构:支持应用多租户部署和管理
使用Spring Boot和Spring Cloud实现多租户架构:支持应用多租户部署和管理
- 一、概述
- 1 什么是多租户架构?
- 2 多租户架构的优势
- 3 实现多租户架构的技术选择
- 二、设计思路
- 1 架构选型
- 1.1 Spring Boot
- 1.2 Spring Cloud
- 2 数据库设计
- 3 应用多租户部署
- 3.1 应用隔离
- 3.2 应用配置
- 4 租户管理
- 4.1 租户信息维护
- 4.2 租户权限控制
- 三、技术实现
- 1 Spring Boot中的多租户实现
- 1.1 多数据源实现
- 1.2 动态路由实现
- 2 Spring Cloud中的多租户实现
- 2.1 服务注册与发现
- 2.2 配置中心
- 2.3 负载均衡
- 2.4 API
- 四、 应用场景
- 1 私有云环境
- 2 公有云环境
- 3 企业级应用
- 五、实现步骤
- 1 搭建Spring Boot和Spring Cloud环境
- 2 修改数据库设计
- 3 实现应用多租户部署
- 4 实现租户管理
- 六、小结回顾
一、概述
1 什么是多租户架构?
多租户架构是指在一个应用中支持多个租户(Tenant)同时访问,每个租户拥有独立的资源和数据,并且彼此之间完全隔离。通俗来说,多租户就是把一个应用按照客户的需求“分割”成多个独立的实例,每个实例互不干扰。
2 多租户架构的优势
- 更好地满足不同租户的个性化需求。
- 可以降低运维成本,减少硬件、网络等基础设施的投入。
- 节约开发成本,通过复用代码,快速上线新的租户实例。
- 增强了系统的可扩展性和可伸缩性,支持水平扩展,每个租户的数据和资源均可管理和控制。
3 实现多租户架构的技术选择
对于实现多租户架构技术不是最重要的最重要的是正确的架构思路。但是选择正确的技术可以更快地实现多租户架构。
二、设计思路
1 架构选型
基于Java开发多租户应用推荐使用Spring Boot和Spring Cloud。Spring Boot能快速搭建应用并提供许多成熟的插件。Spring Cloud则提供了许多实现微服务架构的工具和组件。
1.1 Spring Boot
使用Spring Boot可以简化项目的搭建过程自动配置许多常见的第三方库和组件,减少了开发人员的工作量。
@RestController
public class TenantController {@GetMapping("/hello")public String hello(@RequestHeader("tenant-id") String tenantId) {return "Hello, " + tenantId;}
}
1.2 Spring Cloud
在架构多租户的系统时Spring Cloud会更加有用。Spring Cloud提供了一些成熟的解决方案,如Eureka、Zookeeper、Consul等,以实现服务发现、负载均衡等微服务功能。
2 数据库设计
在多租户环境中数据库必须为每个租户分别存储数据并确保数据隔离。我们通常使用以下两种方式实现:
- 多个租户共享相同的数据库,每个表中都包含tenant_id这一列,用于区分不同租户的数据。
- 为每个租户创建单独的数据库,每个数据库内的表结构相同,但数据相互隔离。
3 应用多租户部署
为了实现多租户在应用部署时我们需要考虑以下两个问题。
3.1 应用隔离
在多租户环境中不同租户需要访问不同的资源,因此需要进行应用隔离。可以通过构建独立的容器或虚拟机、使用命名空间等方式实现。Docker就是一种非常流行的隔离容器技术。
3.2 应用配置
由于每个租户都有自己的配置需求因此需要为每个租户分别设置应用配置信息,例如端口号、SSL证书等等。这些配置可以存储在数据库中,也可以存储在云配置中心中。
4 租户管理
在多租户系统中需要能够管理不同租户的数据和资源,同时需要为每个租户分配相应的权限。解决方案通常包括以下两部分。
4.1 租户信息维护
租户信息的维护包括添加、修改、删除、查询等操作,要求能够根据租户名称或租户ID快速查找对应的租户信息。
CREATE TABLE tenant (id BIGINT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(50) NOT NULL UNIQUE,description VARCHAR(255),created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
4.2 租户权限控制
在多租户应用中必须为每个租户分别设置对系统资源的访问权限。例如,A租户和B租户不能访问彼此的数据。
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/api/tenant/**").hasRole("ADMIN").anyRequest().authenticated().and().formLogin();}@Autowiredpublic void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService()).passwordEncoder(new BCryptPasswordEncoder()).and().inMemoryAuthentication().withUser("admin").password(new BCryptPasswordEncoder().encode("123456")).roles("ADMIN");}
}
三、技术实现
1 Spring Boot中的多租户实现
在Spring Boot中可以通过多数据源和动态路由来实现多租户机制。
1.1 多数据源实现
多数据源是指为不同的租户配置不同的数据源,使得每个租户都可以访问自己的独立数据。具体实现方法如下:
@Configuration
public class DataSourceConfig {@Bean(name = "dataSourceA")@ConfigurationProperties(prefix = "spring.datasource.a")public DataSource dataSourceA() {return DataSourceBuilder.create().build();}@Bean(name = "dataSourceB")@ConfigurationProperties(prefix = "spring.datasource.b")public DataSource dataSourceB() {return DataSourceBuilder.create().build();}@Bean(name = "dataSourceC")@ConfigurationProperties(prefix = "spring.datasource.c")public DataSource dataSourceC() {return DataSourceBuilder.create().build();}
}
以上代码是配置了三个数据源分别对应三个租户。然后在使用时,可以使用注解标记需要连接的数据源。
@Service
public class ProductService {@Autowired@Qualifier("dataSourceA")private DataSource dataSource;// ...
}
1.2 动态路由实现
动态路由是指根据请求的URL或参数动态地切换到对应租户的数据源。具体实现如下:
public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return TenantContextHolder.getTenantId();}
}@Configuration
public class DataSourceConfig {@Bean(name = "dataSource")@ConfigurationProperties(prefix = "spring.datasource")public DataSource dataSource() {return DataSourceBuilder.create().type(DynamicDataSource.class).build();}
}
以上是动态路由的核心代码DynamicDataSource
继承自AbstractRoutingDataSource
,通过determineCurrentLookupKey()
方法动态获得租户ID,然后切换到对应的数据源。
2 Spring Cloud中的多租户实现
在Spring Cloud中可以通过服务注册与发现、配置中心、负载均衡等方式实现多租户机制。
2.1 服务注册与发现
使用Spring Cloud中的Eureka实现服务注册与发现。每个租户的服务都在注册中心以不同的应用名称进行注册,客户端可以通过服务名称来访问对应租户的服务。
2.2 配置中心
使用Spring Cloud Config作为配置中心。配置文件以租户ID进行区分,客户端通过读取对应租户的配置文件来获取配置信息。
2.3 负载均衡
使用Spring Cloud Ribbon作为负载均衡器。根据请求的URL或参数选择对应租户的服务实例进行请求转发。
2.4 API
在API网关层面实现多租户机制根据请求的URL或参数判断所属租户,并转发到对应租户的服务实例。
四、 应用场景
1 私有云环境
私有云环境指的是由企业自行搭建的云环境,不对外提供服务,主要应用于企业内部的数据存储、管理、共享和安全控制。相较于公有云,私有云的优点在于可以更好地保护企业核心数据,同时也能够满足企业对于数据安全性和可控性的要求。
2 公有云环境
公有云环境指的是由云服务商搭建并对外提供服务的云环境,用户可以根据需要购买相应的云服务,如云存储、云计算、云数据库等。相较于私有云,公有云的优点在于具有成本低廉、弹性伸缩、全球化部署等特点,能够更好地满足企业快速发展的需求。
3 企业级应用
企业级应用是指面向企业客户的应用程序,主要包括ERP、CRM、OA等一系列应用系统。这类应用的特点在于功能强大、流程复杂、数据量大,需要满足企业的高效率、高可靠性、高安全性和易维护性等要求。在云计算环境下,企业可以将这些应用部署在私有云或公有云上,减少了硬件设备的投入和维护成本,提高了管理效率。
五、实现步骤
1 搭建Spring Boot和Spring Cloud环境
首先需要在Maven项目中引入以下依赖:
<!-- Spring Boot -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency><!-- Spring Cloud -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>2020.0.3</version><type>pom</type><scope>import</scope>
</dependency>
然后需要在application.yml
中配置相应的参数,如下所示:
spring:datasource:url: jdbc:mysql://localhost:3306/appdb?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghaiusername: rootpassword: 123456mybatis:type-aliases-package: com.example.demo.modelmapper-locations: classpath:mapper/*.xmlserver:port: 8080eureka:client:serviceUrl:defaultZone: http://localhost:8761/eureka/management:endpoints:web:exposure:include: "*"
其中datasource.url
为数据库连接的URL,username
和password
为数据库连接的账号和密码;server.port
为Spring Boot应用启动的端口;eureka.client.serviceUrl.defaultZone
为Eureka服务注册中心的URL。
2 修改数据库设计
接下来需要对数据库进行相应的修改,以支持多租户部署。具体来说,我们需要在数据库中添加一个与租户相关的字段,以便在应用中区分不同的租户。
3 实现应用多租户部署
接着需要在代码中实现应用的多租户部署功能。具体来说,我们需要为每个租户实例化对应的Spring Bean,并根据租户ID将请求路由到相应的Bean中去处理。
以下是一个简单的实现示例:
@Configuration
public class MultiTenantConfig {// 提供对应租户的数据源@Beanpublic DataSource dataSource(TenantRegistry tenantRegistry) {return new TenantAwareDataSource(tenantRegistry);}// 多租户Session工厂@Bean(name = "sqlSessionFactory")public SqlSessionFactory sqlSessionFactory(DataSource dataSource)throws Exception {SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();sessionFactory.setDataSource(dataSource);return sessionFactory.getObject();}// 动态切换租户@Beanpublic MultiTenantInterceptor multiTenantInterceptor(TenantResolver tenantResolver) {MultiTenantInterceptor interceptor = new MultiTenantInterceptor();interceptor.setTenantResolver(tenantResolver);return interceptor;}// 注册拦截器@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(multiTenantInterceptor());}// 注册租户信息@Beanpublic TenantRegistry tenantRegistry() {return new TenantRegistryImpl();}// 解析租户ID@Beanpublic TenantResolver tenantResolver() {return new HeaderTenantResolver();}}
其中MultiTenantConfig
是多租户部署的核心配置类,它提供了对应租户数据源、多租户Session工厂、动态切换租户等功能。
4 实现租户管理
最后需要实现一个租户管理的功能,以便在系统中管理不同的租户。具体来说,我们可以使用Spring Cloud的服务注册与发现组件Eureka来注册每个租户的实例,并在管理界面中进行相应的操作。另外,我们还需要为每个租户提供一个独立的数据库,以保证数据隔离性。
六、小结回顾
本文详细介绍了如何使用Spring Boot和Spring Cloud实现一个支持多租户部署的应用。主要包括搭建Spring Boot和Spring Cloud环境、修改数据库设计、实现应用多租户部署、实现租户管理等方面。应用场景主要包括SaaS应用、多租户云服务等。优劣势主要体现在提升了应用的可扩展性和可维护性,但也增加了部署和管理的复杂度。未来的改进方向可以考虑进一步提升多租户管理的自动化程度,减少人工干预和错误率。
相关文章:
使用Spring Boot和Spring Cloud实现多租户架构:支持应用多租户部署和管理
使用Spring Boot和Spring Cloud实现多租户架构:支持应用多租户部署和管理 一、概述1 什么是多租户架构?2 多租户架构的优势3 实现多租户架构的技术选择 二、设计思路1 架构选型1.1 Spring Boot1.2 Spring Cloud 2 数据库设计3 应用多租户部署3.1 应用隔离…...

智聚北京!相约全球人力资源数智化峰会
人力资源是推动经济社会发展的第一资源。作为我国经济压舱石的中央企业在对标世界一流企业和管理提升方面的持续创新,各行业领军企业围绕组织变革、管理升级、全球化发展走深走实。人力资源管理正从传统职能管理与管控,向紧贴业务战略实现、组织边界和人…...

工业缺陷检测数据及代码(附代码)
介绍 目前,基于机器视觉的表面缺陷检测设备已广泛取代人工视觉检测,在包括3C、汽车、家电、机械制造、半导体与电子、化工、制药、航空航天、轻工等多个行业领域得到应用。传统的基于机器视觉的表面缺陷检测方法通常采用常规图像处理算法或人工设计的特征加分类器。一般而言…...

CentOS 安装MongoDB 6.0
一、安装依赖 yum install libcurl openssl xz-libs 二、下载安装包 安装包下载地址https://www.mongodb.com/try/download/community这里我选择的是 选择RedHat / CentOS 7.0平台的原因是我的操作系统使用的是CentOS 7.0的,需要下载与操作系统匹配的安装包 三、…...

美团面试,被拷打了一小时....
刚从美团走出来,被拷打了一小时…越想越觉得可惜,回想面试经过,好好总结了几个点,发现面试没过的主要原因是在几个关键的问题没有给到面试官想要的答案。从而失去了这次宝贵的机会。 根据你的工作经历,说说你对质量保证…...

017+C语言中函数栈帧的创建与销毁(VS2022环境)
0.前言 您好,这里是limou3434的一篇个人博文,感兴趣的话您也可以看看我的其他文章。本次我将和您一起学习在C语言中函数栈帧的概念。 1.学习函数栈帧的意义 局部变量是怎么穿创建的?为什么局部变量的值是随机的函数是怎么传参的࿱…...

马斯克们叫停 GPT-5,更像是场行为艺术
目录 01 联名信说了什么? 02 发起方是谁? 03 谁签署了联名信? 04 联名信有哪些问题?三巨头的另外两位 Sam Altman 的表态 其他值得关注的署名者 比如马斯克。 另一个位于前列的署名者是 Stability AI 的创始人 Emad Most…...
事务基础知识
第13章 事务基础知识 1. 数据库事务概述 1.1 基本概念 **事务:**一组逻辑操作单元,使数据从一种状态变换到另一种状态。 **事务处理的原则:**保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种…...

国产高性能DSP音频处理芯片的工作原理以及应用领域
DSP芯片是数字信号处理器的简称,它是一种专门用于数字信号处理的微处理器,它可以对数字信号进行高速运算和处理。DSP是一类嵌入式通用可编程微处理器,主要用于实现对信号的采集、识别、变换、增强、控制等算法处理,是各类嵌入式系…...

BEVDet4D 论文学习
1. 解决了什么问题? 单帧数据包含的信息很有限,制约了目前基于视觉的多相机 3D 目标检测方法的性能,尤其是关于速度预测任务,要远落后于基于 LiDAR 和 radar 的方法。 2. 提出了什么方法? BEVDet4D 将 BEVDet 方法从…...
【设计模式与范式:创建型】43 | 单例模式(下):如何设计实现一个集群环境下的分布式单例模式?
上两节课中,我们针对单例模式,讲解了单例的应用场景、几种常见的代码实现和存在的问题,并粗略给出了替换单例模式的方法,比如工厂模式、IOC 容器。今天,我们再进一步扩展延伸一下,一块讨论一下下面这几个问…...

Metal入门学习:绘制渲染三角形
一、编程指南PDF下载链接(中英文档) 1、Metal编程指南PDF链接 https://github.com/dennie-lee/ios_tech_record/raw/main/Metal学习PDF/Metal 编程指南.pdf 2、Metal着色语言(Metal Shader Language:简称MSL)编程指南PDF链接 https://github.com/dennie-lee/ios_te…...

python 中常见变量类型
数值 a 10 b 123 … 字符串 在python中 用单引号’‘和双引号""括起来的都是字符串,不使用引号括起来的不是字符串,字符串是使用最多的数据类型,用来表示一段文本信息。 比如: a ‘123’ b “123” 字符串之间可以用加法运算…...

SVN使用教程(一)
文章目录 前言一、SVN是什么?二、SVN和Git对比,有什么优势?三、SVN主要应用四、SVN仓库五、安装SVN客户端 前言 提示:这里可以添加本文要记录的大概内容: 在制作系统或者写文档,都需要用于管理和跟踪开发…...
【5.19】四、性能测试—指标、种类
目录 4.1 性能测试概述 4.2 性能测试的指标 4.3 性能测试的种类 为了追求高质量、高效率的生活与工作,人们对软件产品的性能要求越来越高,例如软件产品要足够稳定、响应速度足够快,在用户量、工作量较大时也不会出现崩溃或卡顿等现象。人们…...

Windows平台上的5种敏捷软件开发(过程)模型
我是荔园微风,作为一名在IT界整整25年的老兵,今天总结一下Windows平台上的5种敏捷软件开发(过程)模型。 说到这个问题,你必须先知道除了敏捷模型还有没有其他什么模型?同时要比较模型的区别,首先还要看看什么叫软件开…...
一文实现部署AutoGPT
一文实现部署AutoGPT 简介AutoGPT的概述AutoGPT的用途和优势 预备知识Python基础机器学习基础自然语言处理基础 环境设置Python环境安装和配置需要的库和框架的安装,例如PyTorch, Transformers等 AutoGPT模型加载如何下载和加载预训练的AutoGPT模型模型参数和配置 使…...

数值计算 - 误差的来源
误差的来源是多方面的,但主要来源为:过失误差,描述误差,观测误差,截断误差和舍入误差。 过失误差 过失误差是由设备故障和人为的错误所产生的误差,在由于每个人都有“权利”利用机器进行数值计算,所以在计算…...

【软件测试】5年测试老鸟总结,自动化测试成功实施,你应该知道的...
目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 自动化测试 Pytho…...

【Hadoop】二、Hadoop MapReduce与Hadoop YARN
文章目录 二、Hadoop MapReduce与Hadoop YARN1、Hadoop MapReduce1.1、理解MapReduce思想1.2、Hadoop MapReduce设计构思1.3、Hadoop MapReduce介绍1.4、Hadoop MapReduce官方示例1.5、Map阶段执行流程1.6、Reduce阶段执行流程1.7、Shuffle机制 2、Hadoop YARN2.1、Hadoop YARN…...

Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...
DiscuzX3.5发帖json api
参考文章:PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下,适配我自己的需求 有一个站点存在多个采集站,我想通过主站拿标题,采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...
前端调试HTTP状态码
1xx(信息类状态码) 这类状态码表示临时响应,需要客户端继续处理请求。 100 Continue 服务器已收到请求的初始部分,客户端应继续发送剩余部分。 2xx(成功类状态码) 表示请求已成功被服务器接收、理解并处…...