Home > Back-end >  How to create multiple reactive MongoDB connectors with SpringBoot
How to create multiple reactive MongoDB connectors with SpringBoot

Time:07-11

I have a SpringBoot application that currently uses autoconfiguration to connect to MongoDB. I need to add more MongoDB datasources.

I tried to manually create them but I'm struggling to find the right configuration.

I've found Spring: 2 Repositories out of a single Entity and Multiple MongoDB connectors with Spring Boot but the underlying classes are outdated and it's throwing the error:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: Timeout on blocking read for 5000000000 NANOSECONDS

CodePudding user response:

Spring Boot autoconfig works great for one data source but doesn't support multiple connectors. 

To do that we have to manually create the Repository instance, but  because they are dynamically implemented from an interface is not possible to create the concrete instance and add parameters. 

Steps:

  1. Disable Spring Auto config for Mongo so we can provide the beans manually
  2. Create a ReactiveMongoTemplate  bean for each connector needed. This will be used by Spring to create new ReactiveRepositories  instances
  3. Create the ReactiveRepository  instances in different sibling packages
  4. Finally create a @Configuration  for each connector needed and specify the package where the ReactiveRepository  instance resides (see example below)

//# 1. Disable autoconfig
@SpringBootApplication(exclude = {
    MongoAutoConfiguration.class,
    MongoDataAutoConfiguration.class
})
public class XyzApplication {
...
}

//# 2. Create reactive template beans
package com.xyz.config;
...
@Configuration
public class MultipleMongoConfig {

    @Value("${mongodb.primary.uri}")
    private String mongodbPrimaryUri;

    @Value("${mongodb.readonly.uri}")
    private String mongodbSecondaryUri;

    @Primary
    @Bean
    public ReactiveMongoTemplate primaryMongoTemplate() {
        return new ReactiveMongoTemplate(
            new SimpleReactiveMongoDatabaseFactory(
                new ConnectionString(mongodbPrimaryUri)));
    }

    @Primary
    @Bean
    public ReactiveMongoTemplate secondaryMongoTemplate() {
        return new ReactiveMongoTemplate(
            new SimpleReactiveMongoDatabaseFactory(
                new ConnectionString(mongodbSecondaryUri)));
    }
}

Steps 1 and 2 will replace Spring autoconfigure. Then 3 and 4 will use this config

//# 3. Create Reactive repositories
// PrimaryRepository.java
package com.xyz.primary;

@Repository
public interface PrimaryRepository extends ReactiveMongoRepository<Xyz, String> {}


// SecondaryRepository.java
pacakge com.xyz.secondary;

@Repository
public interface SecondaryRepository extends ReactiveMongoRepository<Xyz, String> {}

//# 4. Create specifig configs
// PrimaryMongoConfig.java
package com.xyz.config;
...
@Configuration
@EnableReactiveMongoRepositories(
    basePackages = "com.xyz.primary", 
    reactiveMongoTemplateRef = "primaryMongoTemplate")
public class PrimaryMongoConfig {}

// SecondaryMongoConfig.java
pacakge com.xyz.config;
...
@Configuration
@EnableReactiveMongoRepositories(
    basePackages = "com.xyz.secondary",
    reactiveMongoTemplateRef = "secondaryMongoTemplate")
public class SecondaryMongoConfig {}
      

Notes:

  • The respositories have to be in separates sibling pacakges (or at least make sure one is not a subpackage of the other)
  • The key part is to specify the basePackage where the repository is created
  • Because they are in different packages the Repositores could have the same name, but will have to be used in code with their fully qualified name if both are used in the same class.
  • All of the classes are supplied if the spring-boot-data dependency is already present, if you find yourself needing to import the mongodb driver itself, you're in the wrong track.
  • The SimpleReactiveMongDatabaseFactory is created using the connection string, which includes the password and database name, you have to be mindful on how to externalize this configuration. There is another constructor, but I didn't go and tried to create a separate MongoClient instance
  • The existing spring.data.mondgodb.uri can be used but I find it better to create separate properties thus: mongodb.primary.uri and mongodb.secondary.uri were used.

Resources:

  • Related