June 25, 2015

Multiple Mongo Templates in a Spring Boot Application

Hi Readers,
In this post we are going to talk about creating multiple Mongo Templates in a Spring Boot backed application. Spring Boot helps us concentrate on our business logic only and takes care of all the application related configurations. Spring Boot's powerful auto configuration help us writing our applications very fast. 


How Spring Boot Creates a Mongo Connection:

To create MongoTemplate instance through Spring Boot we only need to provide Mongo Server details in Spring Boot specific property keys and Spring Boot on startup automatically creates a Mongo Connection with Mongo Template wrapper and let's us Auto wire wherever we want to use.

Below are the basic properties required for creating a MongoTemplate.


spring.data.mongodb.host= <host name="">
spring.data.mongodb.port= <port number="">
spring.data.mongodb.uri= <db uri=""> (alternative)
spring.data.mongodb.database= <database name="">


Spring Boot has a class called as MongoProperties.java which defines the mandatory property key prefix as 'spring.data.mongodb' (can be seen in the above properties extract). The MongoProperties.java holds all the mongo properties that we wrote in the application.properties. Then there is another class called as MongoDataAutoConfiguration.java which uses the MongoProperties.java as its Properties Configuration Class and is responsible for actually creating the MongoTemplate through one of its factory methods

To connect to two different mongo server I would have required to override all these classes and their behaviors. To avoid this I used a simple technic as described below. 

Configuring Multiple MongoTemplates:

First of all I modified application.properties and added two sets of Mongodb connection details like shown below.



primary.mongodb.host=<primary_mongodb_host>
primary.mongodb.port=<primary_mongodb_port>
primary.mongodb.database=<primary_mongodb_database>

secondary.mongodb.host=<secondary_mongodb_host>
secondary.mongodb.port=<secondary_mongodb_port>
secondary.mongodb.database=<secondary_mongodb_database>


Doing this the Spring Boots default auto-configuration of MongoTemplate would go on toss as it doesn't find the required keys in the properties file. In this case Spring Boot will create a MongoTemplate with default host and post (localhost:27017). Before we end I will also tell how did I avoid that.

Below are the simple classes I created. 

public abstract class AbstractMongoConfig {    
    //Mongo DB Properties    
    private String host, database;    
    private int port;     
    
    //Setter methods go here..     
    
    /*      
     * Method that creates MongoDbFactory     
     * Common to both of the MongoDb connections     
     */    
    public MongoDbFactory mongoDbFactory() throws Exception {        
        return new SimpleMongoDbFactory(new MongoClient(host, port), database);    
    }      

    /*     
     * Factory method to create the MongoTemplate     
     */    
    abstract public MongoTemplate getMongoTemplate() throws Exception;
} 

@Configuration  //Configuration class
@ConfigurationProperties(prefix = "primary.mongodb") //Defines my custom prefix and points to the primary db properties
public class CommonMongoConfig extends AbstractMongoConfig {     
    /**      
     * Implementation of the MongoTemplate factory method      
     * @Bean gives a name (primaryMongoTemplate) to the created MongoTemplate instance      
     * @Primary declares that if MongoTemplate is autowired without providing a specific name, 
     * this is the instance which will be mapped by         default      
     */    
     @Primary    
     @Override    
     public @Bean(name = "primaryMongoTemplate") MongoTemplate getMongoTemplate() throws Exception {        
         return new MongoTemplate(mongoDbFactory());    
     }
}
Look at the @Primary annotation here. It will tell Spring to load this MongoTemplate by default when nothing is provided.


@Configuration  //Configuration 
class@ConfigurationProperties(prefix = "secondary.mongodb")  //Defines my custom prefix and points to the secondary db properties
public class SecondaryMongoConfig extends  AbstractMongoConfig{     
    /**      
      * Implementation of the MongoTemplate factory method      
      * @Bean gives a name (primaryMongoTemplate) to the created MongoTemplate instance      
      * Note that this method doesn't have @Primary       
      */    
    @Override public @Bean(name = "secondaryMongoTemplate") 
    MongoTemplate getMongoTemplate() throws Exception {        
        return new MongoTemplate(mongoDbFactory());    
    }
}

//Using MongoTemplate for primary database
@Autowired
@Qualifier(value = "primaryMongoTemplate") //This is optional as we already have our 'primaryMongoTemplate' set as a default mongoTemplate.
protected MongoTemplate mongoTemplate;   


//Using mongoTemplate for secondary database
@Autowired
@Qualifier(value = "secondaryMongoTemplate")
protected MongoTemplate mongoTemplate;

That's what we need to do. Now we are just left with using the MongoTemplates. Below are the examples how can we use it.