You are on page 1of 14

See discussions, stats, and author profiles for this publication at: https://www.researchgate.

net/publication/321070490

Spring Multi-tenant architecture-practical implementation

Article · August 2016

CITATION READS
1 375

1 author:

Ahmed Ali
University of the Cumberlands
18 PUBLICATIONS   10 CITATIONS   

SEE PROFILE

Some of the authors of this publication are also working on these related projects:

Spring Multi-tenant View project

Services base for Microservice View project

All content following this page was uploaded by Ahmed Ali on 15 November 2017.

The user has requested enhancement of the downloaded file.


Spring Multi-tenant architecture – practical implementation

Ahmed Ali August 02, 2016

Abstract

Multi-tenancy architecture is often used where single instance of software or components run on server
the central idea is that multiple tenant applications share single instance or components stored in the
infrastructure Meta data., In other words, in Multi-tenancy architecture each tenant application not only
needs to develop its own functionalities, but also needs to prepare an infrastructure to allow its tenants
to run customized applications. This article propose implementation models for Multi-tenancy in Spring
as an example, and discusses their trade-offs including their formal notations and application scenarios.

What is Multi-tenancy?

– Multi-tenancy is a principle in software architecture where a single instance of the


software runs on a server, serving multiple tenants

– A tenant is a group of users sharing the same view of the software instance Under
specific privileges

Benefits of Multi-tenancy
Cost savings

What if we try to implements all types of requirements for all application instances?

Assume we have different instance running on different Application Server and all
have the same application what are the issue of this design?

– Number of components increased if the application tries to handle every specific user or
group of users requirements

– Components will explode more if another group of users requirements joins the to
accommodate all permutations and combinations

– Hard to manage the components and leads to lot of refactoring, defects, and post-
production maintenance problems due to complexity

– Components management difficulties at source control level especially for large scale

– Complex build script to deploy each specific application

– Component configuration complexities for spring configuration and bean injection


issues

– Unnecessary other instance of application specific bean creation issues to support multi-
tenancy that leads to memory bloating

– Need to support customizations for existing program functionality for each version at
various levels such as

– Source code level support

– Java server pages (JSPs)

– Controllers

– Delegators

– Service classes

– Data Access Layer classes

– Configuration files

Solution:

Create instance specific beans using spring framework scope functionality by creating
custom scope

• Keep each specific functionality in the same base component


• Differentiate each specific functionality by using a predefined package structure
that starts with specific code by using the pattern for naming
• Keep jsp files under specific folder in webapp for each
• Create specific configuration file to keep all specific configurations at one place
• And more importantly, create new scope class to support instantiation of each
specific bean instead of instantiating each bean (one time at framework level)

Spring MVC snapshot concept

The Spring Web model-view-controller (MVC) framework is designed around a


DispatcherServlet that dispatches requests to handlers, with configurable handler
mappings, view resolution, locale, time zone and theme resolution as well as support
for uploading files. The default handler is based on the @Controller and
@RequestMapping annotations, offering a wide range of flexible handling methods.

Spring configurations for beans definitions

Files involved in MVC configuration:

• Tables definition (definitions-xxx.xml)


• Controller (XXServlet.xml)
• Service definition (xxx.xml)
• DAO definition (xxx.xml and xxx.hbm.xml)
We can see that spring architecture make a clear separation between each layer in the
three tiers architecture.

Multi-tenancy Scenarios
Code level support for multi-tenancy is needed for three types of requirements:
– Scenario 1: Overriding the existing functionality which is unique to each instance
• Screen level:
– adding new fields
– removing fields,
– customizing the labels
– Custom error or validation messages
• Business logic: each instance may need specific business rules implementation
– Overriding the existing functionality
– Scenario 2: new requirement for one instance only (unique to the specific instance )
– Scenario 3: New requirement for all instance that is same for all
– Scenario 4: New requirement that is common for all instance except different for other
instances

Scenario 1: Overriding existing functionality for each instance

Possible requirements:

Screen fields may be different from baseline and different for each instance

Business logic may be different from baseline and different for each instance

Database changes to implement each specific functionality

No impact to Baseline Code:

Common data model, so no impact at database level for each instance.

Since it is common data model, data objects such as entity objects, value objects and
command objects are common for all instances. Changes for one instance are applicable
to all with no business impact

Multi-tenancy Support:

If screen changes are needed:

• Custom screen for each instance

• Changes needed at tiles definition configuration file

• Bean id definition changes in Spring configuration file

• No changes needed at controller level

• Delegator classes need to be created and configured


If business logic changes are needed (Service Layer):

• Custom service class need to be created

• Configuration changes in spring configuration file

• Extend the base class and either override an existing method or add new
method

If database changes are needed (DAO Layer):

• Custom persistence class need to be created

• Extend the base class and either override an existing method or add new
method

• Configuration changes in spring configuration file

• Database changes

• hbm file changes

• Changes to entity object, value object and command object if needed

Scenario 2: New requirement for one instance only (unique to each instance)

• Possible requirements:
- New Screen
- New service classes to accommodate business logic
- Database changes to implement instance specific functionality
• No impact to Baseline Code:
- Since it is common data model, data objects such as entity objects,
value objects and command objects are common for all instances.
Changes for one instance are applicable to all with no business impact
• Multi-tenancy Support:
If new screen is needed:
- Custom screen for each instance
- Changes needed at tiles definition configuration file
- Bean id definition changes in Spring configuration file
- No changes needed at controller level
- Delegator classes need to be created and configured

– At business logic changes are needed (Service Layer):


• Custom service class need to be created
• Configuration changes in spring configuration file
• If applicable, extend the base class and either override an existing method or
add new method

– If database changes are needed (DAO Layer):


• Custom persistence class need to be created
• If needed, extend the base class and either override an existing method or add
new method
• Configuration changes in spring configuration file
• Database changes (through DRR)
• hbm file changes
• Changes to entity object, value object and command object if needed

Scenario 3: New requirement for all each instance that is same for all
• Possible requirements:
- New Screen
- New service classes to accommodate business logic
- Database changes to implement instance specific functionality
• Multi-tenancy Support:
- All the steps are same as Scenario 2 but all the files are put at base
product level instead of instance specific custom package level

Scenario 4: New requirement that is common for more than one instance and
different for other
Possible requirements:
- New Screen
- New service classes to accommodate business logic
- Database changes to implement instance specific functionality
Multi-tenancy Support:
- The requirements that are common for more than one instance follows
scenario 3 flow and all the changes and new files are part of product
level
- The requirements unique for one follow scenario 1 flow and the new
files are placed in respective instance packages

General Guidelines for Multitenant support:

All custom JSP and resource files must be kept under that each instance specific folder in
webapp
If overriding the existing screen, name the new jsp file name same as base jsp filename. This is
really important to retain the navigational flow.
All new instance specific class files must kept in the instance specific package. The format for the
package name is
– <instance code>.<domain>.<hluc name>.class name
Example: ga.benefits.applyforbenefits.ClaimEntry.java
– The classes should be kept in the respective base component. For example, base
ClaimEntry.java file is in uilink.benefits.applyforbenefits package in Benefits component.
So keep the new file in the same component under new package name mentioned
above
Each instance will have its own version of Tiles definitions, message.properties,
errormessage.properties, spring configuration files such as uiconnect-servlet.xml.
– Tiles definition files for the product is renamed as definitions-product.xml
– Tiles definition files for each instance are created as definitions-GA.xml, definitions-
SC.xml and definitions-NC.xml
– Each instance has its own message properties file with the name message-<instance
abbreviation>.xml

Example: Service Tier changes for override functionality


Servie Layer level customizations:
1. Develop new service class file for each istance, extend the base class and put it in the respective
instance specific package
– CalcInstnace1.java in Instnace1.CalcInstnace1.java for instance 1
– CalcInstnace2java in in Instnace2.CalcInstnace1.java for instance 2
– CalcInstnace3.java in Instnace3.CalcInstnace1.java for instance 3
– Note: Make sure that you name the class name exactly same as the base class name
and have two character instance code to it. This is really important to maintain the
naming convention. It is case sensitive
– Modify base class bean configuration in xx-servlet-xxx.xml file to add scope attribute as
scope=“multitenant”. That’s it no other changes needed and no custom bean definitions
are needed.
2. At framework level, created new scope class called MultiTenantScope implementing the Spring’s
interface Scope. Classes implementing the Scope interface are used by Spring to retrieve the
beans instances when the bean factory is created. Our MultiTenantScope class will provide the
bean instances depending on which tenant the application is serving to.

public class TenantScope implements ApplicationContextAware,Scope {

private static ApplicationContext appCtx;

private String PRODUCT_TENANT = "testInstance";

public static HashMap<String,String> multitenantScopeClassMap;

private Map<String, Object> objectMap = Collections.synchronizedMap(new


HashMap<String, Object>());
private Context context = null;

private String tenantName;

@Override

public void setApplicationContext(ApplicationContext appContext)

throws BeansException {

appCtx = appContext;

public static ApplicationContext getApplicationContext() {

return appCtx;

public String getTenantName() {

return tenantName;

public void setTenantName(String tenantName) {

this.tenantName = tenantName;

@SuppressWarnings("rawtypes")

public Object get(String beanName, ObjectFactory<?> objectFactory) {

if (tenantName == null) {

try {

this.tenantName = initTenantName();

} catch (NamingException e) {
e.printStackTrace();

if (multitenantScopeClassMap == null) {

initMultitenantScopeClassMap();

if (objectMap.containsKey(beanName)) {

return objectMap.get(beanName);

if (PRODUCT_TENANT.equalsIgnoreCase(tenantName)) {

objectMap.put(beanName, objectFactory.getObject());

return objectMap.get(beanName);

if (multitenantScopeClassMap.containsKey(beanName)) {

try {

AutowireCapableBeanFactory beanFactory =
appCtx.getAutowireCapableBeanFactory();

String clssNm = multitenantScopeClassMap.get(beanName);

Class myclass = Class.forName(clssNm);

objectMap.put(beanName,

beanFactory.createBean(myclass.newInstance().getClass()));

return objectMap.get(beanName);

} catch (Exception exception) {

throw new RuntimeException("System Error "


+ exception.getMessage());

objectMap.put(beanName, objectFactory.getObject());

return objectMap.get(beanName);

public String initTenantName() throws NamingException{

MultitenantScopeDAO multitenantScopeDAO = new


MultitenantScopeDAOImpl(this.getDataSourceLookUp());

tenantName=multitenantScopeDAO.getSystemParametersInstanceCode();

return tenantName;

public void initMultitenantScopeClassMap(){

try {

MultitenantScopeDAO multitenantScopeDAO = new


MultitenantScopeDAOImpl(this.getDataSourceLookUp());

tenantScopeClassMap = new HashMap<String,String>();

List<AcuityBeanClassesEO> acuityBeanClassesEOList =
multitenantScopeDAO.getMultitenantClasses(tenantName.toUpperCase());

Iterator<AcuityBeanClassesEO> iterator = acuityBeanClassesEOList.iterator();

while(iterator.hasNext()){

AcuityBeanClassesEO acuityBeanClassesEO = iterator.next();

tenantScopeClassMap.put(acuityBeanClassesEO.getPrimaryKey().getBeanId(),acuityBea
nClassesEO.getClassNm());

}catch (Exception e) {
throw new RuntimeException(e);

public Object remove(String name) {

return objectMap.remove(name);

public String getConversationId() {

return "MultiTenantScope";

bean config

<bean id=" serviceImplInstanceOne "


class="ServiceImplInstanceOne " scope="multitenant">
</bean>

Build process for a Specific Instance using Command Line

– You can use either command line or STS Run Configuration utility to compile the source
code targeted for a specific instance

– Pass the profile name of the instance you are targeting compile to the maven install
command as shown below. For example:

– mvn install –P <instanceName>


– Example: to compile for instance one, use mvn install –P instone

Build process for a Specific Instance in IDE using Run Configuration Utility

The source code can be compiled using run configuration utility by passing the maven profile
name as an argument.

To add a new Run Configuration in STS, follow the below steps:

1. Under the Project menu, disable the Build Automatically option


2. Right click on the pom.xml for the project to compile and select the Run Configuration
option in the contextual menu.

3. In the Create, manage and run configurations screen, click the New launch configuration
icon.

4. Assign a name to the new Launch Configuration

5. Select the Base directory for the project to compile.

6. Enter the Goals and Profiles.

7. Click the Run button to start the build process for the project

Summary

Multitenant support at

1. Data Access layer


– Database schema will be shared among the Instances

– Entity object, Value Object and Command will be the same for all Instances. If a
property is required for the Instance, it will be added and will remain null all the time
for other Instances.

2. Presentation layer

– Create Instance specific JSP’s for each screen to be customized

– Add view definition to each Instance Tiles views definitions file

– Business layer

– Create a class for each instance extending the product class. The instance specific class
will override the functionality in the parent class.

– The definition for each bean which needs to be customized (delegator, service, dao,
validator, etc) will be changed to set the bean scope as multitenant. This is required
just for beans which will be customized.

– Autowire properties in the bean to be customized

View publication stats

You might also like