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.

Su San Talks Tech
Su San Talks Tech
Su San Talks Tech
How to Build a Scalable Multi‑Tenant Architecture with Spring Boot & Spring Cloud

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSpring BootSpring CloudSaaS
Su San Talks Tech
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.