Multi-Tenancy implementation using Spring Boot + Mongo

Rajesh Gupta
3 min readMar 12, 2021

What is Multi tenancy?

Multi-tenancy is a way/architecture to serve multiple clients using a single instance of software application. Each client is called a tenant. It means, requests from all tenants will share resources but they won’t have access to other tenant’s data.

Multi-Tenancy Models

There are three ways to achieve multi tenancy based on the degree of (physical) separation of the tenant’s data.

  1. Database per Tenant: Each Tenant has its own database and is isolated from other tenants.

2. Shared Database, Shared Schema: All Tenants share a database and. tables. Every table has a Column with the Tenant/client Identifier. Every query to database will have tenant/client identifier in it’s where clause.

3. Shared Database, Separate Schema: All Tenants share a single database, but have their own schemas and tables.

We will follow approach #1 in this solution.

Problem statement

By default, spring provides capability to connect to only one mongo database instance whose configuration is provided as below -

spring:
data:
mongodb:
uri: mongodb://USER:pwd@localhost:27017/test_db

So there is no support in spring which enables user to connect to multiple mongo databases. To achieve this, we need to override some spring mongo configuration which we will go through below -

Get started
1.
We will start with creating a sample spring boot project from https://start.spring.io/ adding below dependencies -

2. Resolve Tenant Identifier

Every http request from all tenants will have some information to resolve tenant identifier. We will use http request header to pass tenant identifier. Let’s write a spring filter extending OncePerRequestFilter class which will extract tenant identifier from request and set it to TenantContext.

TenantContext is the class which will store tenant information. This class is having a ThreadLocal variable to ensure that each request/thread has access to its tenant information only. We have used variable of type InheritableThreadLocal to allow child threads created from the main thread in our application to use same tenantId of the Parent Thread.

3. Define Data sources

Now it’s time to define tenant datasource configurations.

Now define data sources for all tenants in yaml file.

4. Switch to tenant’s database at runtime

To connect to configured database for a tenant, now we need to override some spring mongo configurations-

a. We need to override getMongoDatabase method from SimpleMongoClientDatabaseFactory.

Above class is having a reference to MultiTenantMongoConfig which is used to store MongoClient per tenant. At startup, we create MongoClient for each configured tenant and store it for future use.

5. Verifying

Let’s create an example of CRUD with an Employee document.

@Data
@Builder
public class Employee {

@Id
private String id;
private String firstName;
private String lastName;
private int age;
private long salary;
}

Also, we need to create repository, service and rest controller as below -

verifying the solution —

Start the application and call the REST API to save employee for tenant_a -

curl -X POST   http://localhost:9090/employee -H 'Content-Type: application/json' -H 'X-Tenant: tenant_a' -d '{"firstName":"ABC","lastName":"XYZ","age":30,"salary":345455}'

This should insert employee record for tenant_a.

Now call below API to confirm the behaviour-

curl -X GET   http://localhost:9090/employee/6045fcc00c38b75e8d154933 -H 'Content-Type: application/json' -H 'X-Tenant: tenant_a'

You should be able to get data which we just inserted.

Now call below same API for tenant_b.

curl -X GET   http://localhost:9090/employee/6045fcc00c38b75e8d154933 -H 'Content-Type: application/json' -H 'X-Tenant: tenant_b'

This should not return data which we inserted for tenant_a.

Conclusion

With the help of above solution, we are able to connect multiple mongo databases. Once an application receives a request with X-tenant header, application goes to tenant’s configured database and return dataset from it.

Github

If you would like to refer to the full code, do check

https://github.com/rajgupta5989/spring-boot-multi-tenancy-mongo

--

--