Connecting to MongoDB

One of the first tasks when using MongoDB and Spring is to create a MongoClient object using the IoC container. There are two main ways to do this, either by using Java-based bean metadata or by using XML-based bean metadata.

For those not familiar with how to configure the Spring container using Java-based bean metadata instead of XML-based metadata, see the high-level introduction in the reference docs here as well as the detailed documentation here.

Registering a Mongo Instance

The following example shows an example to register an instance of a MongoClient:

Registering MongoClient
  • Imperative

  • Reactive

  • XML

@Configuration
public class AppConfig {

  /*
   * Use the standard Mongo driver API to create a com.mongodb.client.MongoClient instance.
   */
   public @Bean com.mongodb.client.MongoClient mongoClient() {
       return com.mongodb.client.MongoClients.create("mongodb://localhost:27017");
   }
}
@Configuration
public class AppConfig {

  /*
   * Use the standard Mongo driver API to create a com.mongodb.client.MongoClient instance.
   */
   public @Bean com.mongodb.reactivestreams.client.MongoClient mongoClient() {
       return com.mongodb.reactivestreams.client.MongoClients.create("mongodb://localhost:27017");
   }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation=
"
http://www.springframework.org/schema/data/mongo https://www.springframework.org/schema/data/mongo/spring-mongo.xsd
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- Default bean name is 'mongo' -->
    <mongo:mongo-client host="localhost" port="27017"/>

</beans>

This approach lets you use the standard MongoClient instance, with the container using Spring’s MongoClientFactoryBean/ReactiveMongoClientFactoryBean. As compared to instantiating a MongoClient instance directly, the FactoryBean has the added advantage of also providing the container with an ExceptionTranslator implementation that translates MongoDB exceptions to exceptions in Spring’s portable DataAccessException hierarchy for data access classes annotated with the @Repository annotation. This hierarchy and the use of @Repository is described in Spring’s DAO support features.

The following example shows an example of a Java-based bean metadata that supports exception translation on @Repository annotated classes:

Registering a MongoClient via MongoClientFactoryBean / ReactiveMongoClientFactoryBean
  • Imperative

  • Reactive

@Configuration
public class AppConfig {

    /*
     * Factory bean that creates the com.mongodb.client.MongoClient instance
     */
     public @Bean MongoClientFactoryBean mongo() {
          MongoClientFactoryBean mongo = new MongoClientFactoryBean();
          mongo.setHost("localhost");
          return mongo;
     }
}
@Configuration
public class AppConfig {

    /*
     * Factory bean that creates the com.mongodb.reactivestreams.client.MongoClient instance
     */
     public @Bean ReactiveMongoClientFactoryBean mongo() {
          ReactiveMongoClientFactoryBean mongo = new ReactiveMongoClientFactoryBean();
          mongo.setHost("localhost");
          return mongo;
     }
}

To access the MongoClient object created by the FactoryBean in other @Configuration classes or your own classes, use a private @Autowired MongoClient mongoClient; field.

The MongoDatabaseFactory Interface

While MongoClient is the entry point to the MongoDB driver API, connecting to a specific MongoDB database instance requires additional information, such as the database name and an optional username and password. With that information, you can obtain a MongoDatabase object and access all the functionality of a specific MongoDB database instance. Spring provides the org.springframework.data.mongodb.core.MongoDatabaseFactory & org.springframework.data.mongodb.core.ReactiveMongoDatabaseFactory interfaces, shown in the following listing, to bootstrap connectivity to the database:

  • Imperative

  • Reactive

public interface MongoDatabaseFactory {

  MongoDatabase getDatabase() throws DataAccessException;

  MongoDatabase getDatabase(String dbName) throws DataAccessException;
}
public interface ReactiveMongoDatabaseFactory {

  Mono<MongoDatabase> getDatabase() throws DataAccessException;

  Mono<MongoDatabase> getDatabase(String dbName) throws DataAccessException;
}

The following sections show how you can use the container with either Java-based or XML-based metadata to configure an instance of the MongoDatabaseFactory interface. In turn, you can use the MongoDatabaseFactory / ReactiveMongoDatabaseFactory instance to configure MongoTemplate / ReactiveMongoTemplate.

Instead of using the IoC container to create an instance of the template, you can use them in standard Java code, as follows:

  • Imperative

  • Reactive

public class MongoApplication {

  public static void main(String[] args) throws Exception {

    MongoOperations mongoOps = new MongoTemplate(new SimpleMongoClientDatabaseFactory(MongoClients.create(), "database"));

    // ...
  }
}

The code in bold highlights the use of SimpleMongoClientDbFactory and is the only difference between the listing shown in the getting started section. Use SimpleMongoClientDbFactory when choosing com.mongodb.client.MongoClient as the entrypoint of choice.

public class ReactiveMongoApplication {

  public static void main(String[] args) throws Exception {

    ReactiveMongoOperations mongoOps = new MongoTemplate(new SimpleReactiveMongoDatabaseFactory(MongoClients.create(), "database"));

    // ...
  }
}

Registering a MongoDatabaseFactory / ReactiveMongoDatabaseFactory

To register a MongoDatabaseFactory/ ReactiveMongoDatabaseFactory instance with the container, you write code much like what was highlighted in the previous section. The following listing shows a simple example:

  • Imperative

  • Reactive

@Configuration
public class MongoConfiguration {

  @Bean
  public MongoDatabaseFactory mongoDatabaseFactory() {
    return new SimpleMongoClientDatabaseFactory(MongoClients.create(), "database");
  }
}
@Configuration
public class ReactiveMongoConfiguration {

  @Bean
  public ReactiveMongoDatabaseFactory mongoDatabaseFactory() {
    return new SimpleReactiveMongoDatabaseFactory(MongoClients.create(), "database");
  }
}

MongoDB Server generation 3 changed the authentication model when connecting to the DB. Therefore, some of the configuration options available for authentication are no longer valid. You should use the MongoClient-specific options for setting credentials through MongoCredential to provide authentication data, as shown in the following example:

  • Java

  • XML

@Configuration
public class MongoAppConfig extends AbstractMongoClientConfiguration {

  @Override
  public String getDatabaseName() {
    return "database";
  }

  @Override
  protected void configureClientSettings(Builder builder) {

    builder
        .credential(MongoCredential.createCredential("name", "db", "pwd".toCharArray()))
        .applyToClusterSettings(settings  -> {
          settings.hosts(singletonList(new ServerAddress("127.0.0.1", 27017)));
        });
  }
}
<mongo:db-factory dbname="database" />

Username and password credentials used in XML-based configuration must be URL-encoded when these contain reserved characters, such as :, %, @, or ,. The following example shows encoded credentials: m0ng0@dmin:mo_res:bw6},Qsdxx@admin@databasem0ng0%40dmin:mo_res%3Abw6%7D%2CQsdxx%40admin@database See section 2.2 of RFC 3986 for further details.

If you need to configure additional options on the com.mongodb.client.MongoClient instance that is used to create a SimpleMongoClientDbFactory, you can refer to an existing bean as shown in the following example. To show another common usage pattern, the following listing shows the use of a property placeholder, which lets you parametrize the configuration and the creation of a MongoTemplate:

  • Java

  • XML

@Configuration
@PropertySource("classpath:/com/myapp/mongodb/config/mongo.properties")
public class MongoAppConfig extends AbstractMongoClientConfiguration {

  @Autowired
  Environment env;

  @Override
  public String getDatabaseName() {
    return "database";
  }

  @Override
  protected void configureClientSettings(Builder builder) {

    builder.applyToClusterSettings(settings -> {
    settings.hosts(singletonList(
          new ServerAddress(env.getProperty("mongo.host"), env.getProperty("mongo.port", Integer.class))));
    });

    builder.applyToConnectionPoolSettings(settings -> {

      settings.maxConnectionLifeTime(env.getProperty("mongo.pool-max-life-time", Integer.class), TimeUnit.MILLISECONDS)
          .minSize(env.getProperty("mongo.pool-min-size", Integer.class))
          .maxSize(env.getProperty("mongo.pool-max-size", Integer.class))
          .maintenanceFrequency(10, TimeUnit.MILLISECONDS)
          .maintenanceInitialDelay(11, TimeUnit.MILLISECONDS)
          .maxConnectionIdleTime(30, TimeUnit.SECONDS)
          .maxWaitTime(15, TimeUnit.MILLISECONDS);
    });
  }
}
<context:property-placeholder location="classpath:/com/myapp/mongodb/config/mongo.properties"/>

<mongo:mongo-client host="${mongo.host}" port="${mongo.port}">
  <mongo:client-settings connection-pool-max-connection-life-time="${mongo.pool-max-life-time}"
    connection-pool-min-size="${mongo.pool-min-size}"
    connection-pool-max-size="${mongo.pool-max-size}"
    connection-pool-maintenance-frequency="10"
    connection-pool-maintenance-initial-delay="11"
    connection-pool-max-connection-idle-time="30"
    connection-pool-max-wait-time="15" />
</mongo:mongo-client>

<mongo:db-factory dbname="database" mongo-ref="mongoClient"/>

<bean id="anotherMongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
  <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
</bean>