How to Build a Scalable Multi‑Tenant Architecture with Spring Boot & Spring Cloud
This article explains the concept, advantages, design considerations, and step‑by‑step implementation of a multi‑tenant architecture using Spring Boot and Spring Cloud, covering tenant isolation, database strategies, dynamic routing, security configuration, deployment scenarios, and provides complete code examples for building SaaS‑ready applications.
Overview
What is multi‑tenant architecture?
Multi‑tenant architecture allows multiple tenants to access a single application simultaneously, each tenant having isolated resources and data. In simple terms, the application is divided into independent instances per customer, with no interference between them.
Advantages of multi‑tenant architecture
Better meet personalized needs of different tenants.
Reduce operation costs and infrastructure investment.
Save development costs by reusing code and quickly launching new tenant instances.
Improve scalability and support horizontal expansion, with each tenant’s data and resources manageable and controllable.
Technical choices for implementing multi‑tenant architecture
While the correct architectural thinking is most important, choosing appropriate technologies can accelerate implementation.
Design Ideas
Architecture selection
For Java‑based multi‑tenant applications, Spring Boot and Spring Cloud are recommended. Spring Boot quickly builds applications with many mature plugins, and Spring Cloud provides tools for microservice architecture.
Spring Boot
Spring Boot simplifies project setup by auto‑configuring common third‑party libraries and components, reducing developer effort.
@RestController
public class TenantController {
@GetMapping("/hello")
public String hello(@RequestHeader("tenant-id") String tenantId) {
return "Hello, " + tenantId;
}
}Spring Cloud
Spring Cloud offers mature solutions such as Eureka, Zookeeper, Consul for service discovery, load balancing, and other microservice functions.
Database design
In a multi‑tenant environment, the database must store each tenant’s data separately and ensure isolation. Two common approaches are:
All tenants share the same database, with a tenant_id column in each table to distinguish data.
Each tenant has a dedicated database with identical schema, keeping data isolated.
Multi‑tenant deployment considerations
Application isolation
Different tenants need access to different resources, which can be achieved by deploying independent containers or virtual machines, using namespaces, etc. Docker is a popular container isolation technology.
Application configuration
Each tenant may have its own configuration (ports, SSL certificates, etc.) stored in a database or cloud configuration center.
Tenant management
Systems must manage tenant data and resources and assign appropriate permissions. Typical solutions include tenant information maintenance and permission control.
Tenant information maintenance
Operations such as add, modify, delete, and query tenant information, allowing quick lookup by tenant name or 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
);Tenant permission control
Each tenant must have separate access rights to system resources; for example, Tenant A cannot access Tenant B’s data.
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/tenant/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService())
.passwordEncoder(new BCryptPasswordEncoder())
.and()
.inMemoryAuthentication()
.withUser("admin")
.password(new BCryptPasswordEncoder().encode("123456"))
.roles("ADMIN");
}
}Technical Implementation
Spring Boot multi‑tenant implementation
Multi‑tenant mechanisms can be realized through multiple data sources and dynamic routing.
Multiple data source implementation
Configure separate data sources for different tenants.
@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();
}
}Use qualifiers to inject the appropriate data source.
@Service
public class ProductService {
@Autowired
@Qualifier("dataSourceA")
private DataSource dataSource;
// ...
}Dynamic routing implementation
Dynamic routing switches data sources based on the current tenant ID.
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected 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();
}
}Spring Cloud multi‑tenant implementation
Use service registration, configuration center, and load balancing to achieve multi‑tenant mechanisms.
Service registration and discovery
Register each tenant’s services in Eureka with distinct application names; clients access services by name.
Configuration center
Use Spring Cloud Config to store configuration files separated by tenant ID.
Load balancing
Use Spring Cloud Ribbon to route requests to the appropriate tenant’s service instance based on URL or parameters.
API gateway
Implement tenant identification at the gateway layer and forward requests to the corresponding tenant services.
Application Scenarios
Private cloud
Private clouds are built and managed by enterprises for internal data storage, management, sharing, and security control, offering better protection of core data.
Public cloud
Public clouds are provided by cloud service vendors, offering low cost, elastic scaling, and global deployment, suitable for rapid business growth.
Enterprise applications
Enterprise‑level applications such as ERP, CRM, and OA benefit from multi‑tenant architecture to achieve high efficiency, reliability, security, and maintainability.
Implementation Steps
Set up Spring Boot and Spring Cloud environment
Add the following Maven dependencies:
<!-- 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>Configure essential properties in application.yml:
spring:
datasource:
url: jdbc:mysql://localhost:3306/appdb?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
mybatis:
type-aliases-package: com.example.demo.model
mapper-locations: classpath:mapper/*.xml
server:
port: 8080
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
management:
endpoints:
web:
exposure:
include: "*"Modify database design
Add tenant‑related fields to distinguish data belonging to different tenants.
Implement multi‑tenant deployment
Instantiate Spring beans per tenant and route requests based on tenant ID.
@Configuration
public class MultiTenantConfig {
// Provide data source for each tenant
@Bean
public DataSource dataSource(TenantRegistry tenantRegistry) {
return new TenantAwareDataSource(tenantRegistry);
}
// Multi‑tenant SqlSessionFactory
@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
return sessionFactory.getObject();
}
// Dynamic tenant interceptor
@Bean
public MultiTenantInterceptor multiTenantInterceptor(TenantResolver tenantResolver) {
MultiTenantInterceptor interceptor = new MultiTenantInterceptor();
interceptor.setTenantResolver(tenantResolver);
return interceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(multiTenantInterceptor());
}
@Bean
public TenantRegistry tenantRegistry() {
return new TenantRegistryImpl();
}
@Bean
public TenantResolver tenantResolver() {
return new HeaderTenantResolver();
}
}Implement tenant management
Register each tenant’s instance in Eureka and provide a dedicated database to ensure data isolation.
Summary Review
This article detailed how to build a multi‑tenant application with Spring Boot and Spring Cloud, covering environment setup, database redesign, multi‑tenant deployment, and tenant management.
Typical use cases include SaaS applications and multi‑tenant cloud services. While the approach improves scalability and maintainability, it also adds deployment and management complexity. Future work may focus on further automating tenant management to reduce manual effort and error rates.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Su San Talks Tech
Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
