连接 MongoDB
使用 MongoDB 和 Spring 时的首要任务之一,是使用 IoC 容器创建一个 MongoClient 对象。主要有两种方式:使用基于 Java 的 Bean 元数据,或使用基于 XML 的 Bean 元数据。
注册 Mongo 实例
以下示例展示了如何注册一个 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>
这种方式让您使用标准的 MongoClient 实例,容器则使用 Spring 的 MongoClientFactoryBean/ReactiveMongoClientFactoryBean。与直接实例化 MongoClient 实例相比,FactoryBean 的额外优势在于:它还为容器提供了一个 ExceptionTranslator 实现,可将 MongoDB 异常转换为 Spring 可移植的 DataAccessException 体系中的异常,供标注了 @Repository 注解的数据访问类使用。关于该体系以及 @Repository 的使用,请参阅 Spring 的 DAO 支持特性。
以下示例展示了一个基于 Java 的 Bean 元数据示例,它支持对标注了 @Repository 的类进行异常转换:
- 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;
}
}
要在其他 @Configuration 类或您自己的类中访问由 FactoryBean 创建的 MongoClient 对象,可使用 private @Autowired MongoClient mongoClient; 字段。
MongoDatabaseFactory 接口
虽然 MongoClient 是 MongoDB 驱动程序 API 的入口点,但连接到特定的 MongoDB 数据库实例还需要额外的信息,例如数据库名称以及可选的用户名和密码。有了这些信息,您就可以获得一个 MongoDatabase 对象,并访问特定 MongoDB 数据库实例的全部功能。Spring 提供了 org.springframework.data.mongodb.core.MongoDatabaseFactory 与 org.springframework.data.mongodb.core.ReactiveMongoDatabaseFactory 接口(如下列所示),用于引导与数据库的连接:
- 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;
}
以下各节展示了如何结合使用容器与基于 Java 或基于 XML 的元数据,来配置 MongoDatabaseFactory 接口的实例。进而,您可以使用 MongoDatabaseFactory / ReactiveMongoDatabaseFactory 实例来配置 MongoTemplate / ReactiveMongoTemplate。
除了使用 IoC 容器创建模板实例外,您也可以在标准 Java 代码中使用它们,如下所示:
- 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"));
// ...
}
}
注册 MongoDatabaseFactory / ReactiveMongoDatabaseFactory
要向容器注册一个 MongoDatabaseFactory/ ReactiveMongoDatabaseFactory 实例,您编写的代码与上一节中重点介绍的代码非常相似。以下列展示了一个简单示例:
- 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 第 3 代改变了连接数据库时的认证模型。因此,某些用于认证的配置选项不再有效。您应使用 MongoClient 专用选项,通过 MongoCredential 设置凭据来提供认证数据,如下例所示:
- 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@database → m0ng0%40dmin:mo_res%3Abw6%7D%2CQsdxx%40admin@database See section 2.2 of RFC 3986 for further details.
如果您需要在用于创建 SimpleMongoClientDbFactory 的 com.mongodb.client.MongoClient 实例上配置额外选项,可以引用一个已有的 Bean,如下例所示。为展示另一种常见用法模式,下列展示了属性占位符的使用,它让您可以参数化配置以及 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>