Spring Boot Multi-Tenant: Database Isolation, Dynamic DataSource Routing & Spring Cloud
This article explains how to implement multi-tenant architecture using Spring Boot and Spring Cloud, covering database isolation strategies, dynamic data source routing with AbstractRoutingDataSource, tenant management, security configuration, and deployment considerations for SaaS applications.
Overview
Multi-tenant architecture allows a single application to serve multiple tenants with isolated resources and data. Benefits include meeting personalized tenant needs, reducing operational and development costs through code reuse, and enhancing scalability.
Design Approach
Technology Stack
Spring Boot simplifies project setup with auto-configuration; Spring Cloud provides service discovery (Eureka, Consul), configuration center, and load balancing for microservices.
Database Design
Shared database, shared schema: All tenants share tables with a tenant_id column for logical isolation.
Separate databases: Each tenant gets its own database with identical schema, ensuring physical isolation.
Application Isolation & Configuration
Isolation via containers (Docker) or VMs. Tenant-specific configurations (ports, SSL) stored in database or cloud config center.
Tenant Management
Tenant registry: CRUD operations on tenant metadata (ID, name, description). Example SQL for tenant table provided.
Permission control: Spring Security configuration restricting cross-tenant data access, using role-based access (e.g., ADMIN role for /api/tenant/**).
Technical Implementation
Spring Boot Multi-Tenancy
Multiple Data Sources
Define separate DataSource beans per tenant using @ConfigurationProperties with prefixes like spring.datasource.a. Inject via @Qualifier.
@Configuration
public class DataSourceConfig {
@Bean(name = "dataSourceA")
@ConfigurationProperties(prefix = "spring.datasource.a")
public DataSource dataSourceA() {
return DataSourceBuilder.create().build();
}
// dataSourceB, dataSourceC similarly
}Dynamic Data Source Routing
Extend AbstractRoutingDataSource and override determineCurrentLookupKey() to return current tenant ID from a thread-local holder ( TenantContextHolder). Register as primary dataSource bean.
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-Tenancy
Service registration & discovery: Each tenant's services register under distinct application names in Eureka.
Configuration center: Spring Cloud Config serves tenant-specific configuration files.
Load balancing: Ribbon routes requests to appropriate tenant service instances.
API Gateway: Routes incoming requests to tenant-specific services based on URL or parameters.
Application Scenarios
Private cloud: Enterprise-owned, high data control.
Public cloud: Provider-managed, elastic scaling, global deployment.
Enterprise applications: ERP, CRM, OA systems requiring high reliability and security.
Implementation Steps
1. Project Setup
Add Spring Boot Web and Spring Cloud dependencies (version 2020.0.3). Configure application.yml with datasource URL, MyBatis, server port, Eureka client, and actuator endpoints.
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: "*"2. Database Modification
Add tenant-related fields (e.g., tenant_id) to tables for logical isolation.
3. Multi-Tenant Deployment Configuration
Core configuration class MultiTenantConfig provides:
Tenant-aware DataSource via TenantAwareDataSource.
Multi-tenant SqlSessionFactory. MultiTenantInterceptor with TenantResolver (e.g., HeaderTenantResolver reading tenant-id header). TenantRegistry implementation for tenant metadata.
@Configuration
public class MultiTenantConfig {
@Bean
public DataSource dataSource(TenantRegistry tenantRegistry) {
return new TenantAwareDataSource(tenantRegistry);
}
@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
return sessionFactory.getObject();
}
@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();
}
}4. Tenant Management
Use Eureka to register each tenant instance; provide separate databases per tenant for data isolation.
Summary
The article details building a multi-tenant SaaS application with Spring Boot and Spring Cloud. Key trade-offs: shared schema reduces resource overhead but requires strict query filtering; separate databases offer stronger isolation at higher operational cost. Dynamic routing via AbstractRoutingDataSource enables per-request tenant context switching. Spring Cloud components handle service discovery, configuration, and load balancing across tenants. The approach improves extensibility and maintainability but adds deployment complexity. Future improvements could automate tenant provisioning to reduce manual errors.
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.
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.
