Disclaimer
This article represents my perspective on this solution, thus any suggestions, fixes, or discussions will be highly appreciated.
The short story
Let's assume that in any circumstance you have a few databases you need to use to catch/write data within a single Spring Boot application. It can be a result of legacy approach or a result of DBA works etc.
Spring Boot will do it easily for you. Let's start.
The implementation
In many real-world scenarios, Spring Boot applications need to interact with multiple databases. Whether it's due to legacy systems, the need for polyglot persistence, or other reasons, Spring Boot simplifies the task of managing multiple MongoDB databases, even in a reactive environment. In this article, we'll walk you through the implementation steps to seamlessly support multiple MongoDB databases within a single Spring Boot application using reactive programming.
Step 1: Configuration setup
Begin by configuring your Spring Boot application to connect to the MongoDB databases. In your application.properties
(or application.yml
) file, define the connection details for each database, specifying database names, connection URIs, and other necessary properties. To ensure clarity, focus on the essential MongoDB configuration properties.
spring.data.mongodb.databaseOne.database=databaseOne
spring.data.mongodb.databaseTwo.database=databaseTwo
spring.data.mongodb.url=mongodb://localhost:27017/test
spring.autoconfigure.exclude=\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration
In order to use multiple database approach we need to disable MongoDB autoconfigurations by adding the property spring.autoconfigure.exclude
.
Step 2: Creating reactive MongoDB Repositories
To interact with each MongoDB collection, create Spring Data MongoDB repositories for each one. In your project structure, organize these repositories according to the respective database names, enhancing code readability.
package com.demo.repository.database_one;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
public interface CollectionOneRepository extends ReactiveMongoRepository<CollectionOne, String> {
}
package com.demo.repository.database_two;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
public interface CollectionTwoRepository extends ReactiveMongoRepository<CollectionTwo, String> {
}
Step 3: Configuration Properties class
Simplify your code and improve maintainability by creating a configuration properties class that stores configurations per prefix. This step ensures better code organization and allows for additional validations.
package com.demo.config.mongo;
import lombok.Data;
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Primary;
import org.springframework.validation.annotation.Validated;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
@Data
@Validated
@Primary
@ConfigurationProperties(prefix = "spring.data.mongodb", ignoreUnknownFields = false)
public class BaseMongoProperties {
@NotNull private MongoProperties databaseOne;
@NotNull private MongoProperties databaseTwo;
@NotNull @NotEmpty private String uri;
}
Pay attention it need to be marked as a @Primary
configuration, otherwise Spring Boot will throws exception about 2 existing properties. We would like to override these properties by our custom properties.
Step 4: MongoDB Template configuration
Create a main configuration class for MongoDB templates. This class defines two MongoDB templates, one for each database, using the ReactiveMongoTemplate. With this approach we can create one MongoDb client only and reuse it for different MongoTemplates, each for a certain database.
package com.demo.config.mongo;
import com.mongodb.*;
import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
@Configuration
@EnableConfigurationProperties(BaseMongoProperties.class)
public class BaseMongoConfig {
protected static final String DATABASE_ONE_MONGO_TEMPLATE = "databaseOneMongoTemplate";
protected static final String DATABASE_TWO_MONGO_TEMPLATE = "databaseTwoMongoTemplate";
@Bean(name = {DATABASE_ONE_MONGO_TEMPLATE})
public ReactiveMongoTemplate databaseOneMongoTemplate(MongoClient mongoClient, BaseMongoProperties mongoProperties) {
return new ReactiveMongoTemplate(mongoClient, mongoProperties.getDatabaseOne().getDatabase());
}
@Bean(name = {DATABASE_TWO_MONGO_TEMPLATE})
public ReactiveMongoTemplate databaseTwoMongoTemplate(MongoClient mongoClient, BaseMongoProperties mongoProperties) {
return new ReactiveMongoTemplate(mongoClient, mongoProperties.getDatabaseTwo().getDatabase());
}
@Bean
public MongoClient mongoClient(BaseMongoProperties mongoProperties) {
return MongoClients.create(getMongoClientSettings(mongoProperties));
}
private MongoClientSettings getMongoClientSettings(BaseMongoProperties mongoProperties) {
return MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(mongoProperties.getUri()))
.build();
}
}
Step 5: Repository Configuration
We inform Spring Boot about the repositories associated with each MongoDB template by importing ReactiveMongoRepositoriesRegistrar
will register our per database repositories and associate them with the dedicated MongoTemplate
. Create configuration classes for each database, specifying the base package and referencing the correct MongoDB template.
package com.demo.config.mongo;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;
import static com.demo.config.mongo. BaseMongoConfig.DATABASE_ONE_MONGO_TEMPLATE;
@Configuration
@EnableReactiveMongoRepositories(
basePackages = {"com.demo.repository.database_one"},
reactiveMongoTemplateRef = DATABASE_ONE_MONGO_TEMPLATE
)
public class DatabaseOneMongoConfig {
}
package com.demo.config.mongo;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;
import static com.demo.config.mongo.BaseMongoConfig. DATABASE_TWO_MONGO_TEMPLATE;
@Configuration
@EnableReactiveMongoRepositories(
basePackages = {"com.demo.repository.database_two"},
reactiveMongoTemplateRef = DATABASE_TWO_MONGO_TEMPLATE
)
public class DatabaseTwoMongoConfig {
}
Step 6: Integration testing
Lastly, add integration testing with Testcontainers to validate the behavior of your application.
Summary
In this article, we explored the process of seamlessly integrating and managing multiple MongoDB databases within a single Spring Boot application using reactive programming. We began by configuring the application properties, specifying essential MongoDB connection details for each database.
Next, we created Spring Data MongoDB repositories for each MongoDB collection, ensuring an organized project structure that enhances code readability.
To simplify configuration and improve maintainability, we introduced a configuration properties class to store database settings per prefix. This step not only streamlined the code but also allowed for additional validations.
Our main configuration class, BaseMongoConfig, defined two MongoDB templates—one for each database—using the ReactiveMongoTemplate. This setup enabled us to interact with MongoDB collections in a reactive and non-blocking manner.
To inform Spring Boot about the repositories associated with each MongoDB template, we created separate configuration classes for each database. These classes specified the base package and referenced the correct MongoDB template, ensuring that Spring Boot could scan the repositories accurately.
Lastly, we highlighted the importance of integration testing with Testcontainers to verify the behavior of our application, offering readers a practical way to validate their implementations.
By following this comprehensive guide, developers can effectively manage multiple MongoDB databases within their Spring Boot applications while harnessing the power of reactive programming for high concurrency and responsiveness. This approach is invaluable in scenarios where diverse data requirements meet the demands of modern, data-intensive applications.
Resources
- Spring Data MongoDB - Reference Documentation
- Spring Data Reactive Repositories with MongoDB
- EnableReactiveMongoRepositories
Finding my articles helpful? You could give me a caffeine boost to keep them coming! Your coffee donation will keep my keyboard clacking and my ideas brewing. But remember, it's completely optional. Stay tuned, stay informed, and perhaps, keep the coffee flowing!
Top comments (1)
Hello, please can you share the GitHub repository with the complete code?
Some comments may only be visible to logged-in visitors. Sign in to view all comments.