1. 概述
本文将探讨在Spring Boot应用中配置MongoDB连接的多种方法。我们将利用Spring Data MongoDB项目提供的强大能力,该项目为在Spring环境中操作MongoDB数据库提供了丰富的工具和功能。
通过深入研究Spring的灵活配置选项,我们将探索建立数据库连接的各种方法。通过实际示例,我们将为每种方法创建独立的应用程序,以便根据具体需求选择最合适的配置方式。
2. 测试连接
在构建应用之前,我们先创建一个测试类。首先定义一些可重用的常量:
public class MongoConnectionApplicationLiveTest {
private static final String HOST = "localhost";
private static final String PORT = "27017";
private static final String DB = "baeldung";
private static final String USER = "admin";
private static final String PASS = "password";
// 测试用例
}
测试流程包括:运行应用程序,然后尝试在名为"items"的集合中插入文档。插入成功后,数据库会返回"_id",我们将以此判断测试是否通过。现在创建一个辅助方法:
private void assertInsertSucceeds(ConfigurableApplicationContext context) {
String name = "A";
MongoTemplate mongo = context.getBean(MongoTemplate.class);
Document doc = Document.parse("{\"name\":\"" + name + "\"}");
Document inserted = mongo.insert(doc, "items");
assertNotNull(inserted.get("_id"));
assertEquals(inserted.get("name"), name);
}
该方法接收Spring上下文以获取MongoTemplate实例。接着使用Document.parse()从字符串构建简单JSON文档。
这样我们无需创建仓库类或文档类。插入后,我们将验证文档属性是否符合预期。
注意:需要运行真实的MongoDB实例,可以使用Docker容器部署MongoDB。
3. 通过属性配置连接
在Spring Boot应用中,通常使用属性文件配置MongoDB连接。在属性文件中,我们定义主机、端口、认证凭据和数据库名等关键连接信息。后续小节将详细说明这些属性。
3.1. 使用application.properties
最常见的配置方式是在application.properties中提供数据库信息:
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=baeldung
spring.data.mongodb.username=admin
spring.data.mongodb.password=password
所有可用属性都在Spring Boot的MongoProperties类中定义,可在此查看默认值。我们也可以通过应用参数在属性文件中定义任何配置。
在应用类中,需要排除EmbeddedMongoAutoConfiguration类才能正常运行:
@SpringBootApplication(exclude={EmbeddedMongoAutoConfiguration.class})
public class SpringMongoConnectionViaPropertiesApp {
public static void main(String... args) {
SpringApplication.run(SpringMongoConnectionViaPropertiesApp.class, args);
}
}
这些配置足以连接数据库实例。@SpringBootApplication注解包含@EnableAutoConfiguration,它会根据类路径自动发现MongoDB应用。
测试时,使用SpringApplicationBuilder获取应用上下文引用。然后使用之前创建的assertInsertSucceeds方法验证连接有效性:
@Test
public void whenPropertiesConfig_thenInsertSucceeds() {
SpringApplicationBuilder app = new SpringApplicationBuilder(SpringMongoConnectionViaPropertiesApp.class);
app.run();
assertInsertSucceeds(app.context());
}
最终,应用通过application.properties文件成功连接数据库。
3.2. 通过命令行参数覆盖属性
运行应用时,可以通过命令行参数覆盖属性文件。这些参数在使用java命令、mvn命令或IDE配置时传递。具体提供方式取决于使用的命令。
使用mvn运行Spring Boot应用的示例:
mvn spring-boot:run -Dspring-boot.run.arguments='--spring.data.mongodb.port=7017 --spring.data.mongodb.host=localhost'
使用方法:将属性指定为spring-boot.run.arguments的值,属性名前加两个短横线。自Spring Boot 2起,多个属性需用空格分隔。运行命令后不应出现错误。
此方式配置的选项优先级始终高于属性文件。当需要修改应用参数而不改动属性文件时,此方法特别有用,例如凭据变更导致无法连接时。
在测试中模拟此场景,可以在运行应用前设置系统属性,或使用properties方法覆盖application.properties:
@Test
public void givenPrecedence_whenSystemConfig_thenInsertSucceeds() {
System.setProperty("spring.data.mongodb.host", HOST);
System.setProperty("spring.data.mongodb.port", PORT);
System.setProperty("spring.data.mongodb.database", DB);
System.setProperty("spring.data.mongodb.username", USER);
System.setProperty("spring.data.mongodb.password", PASS);
SpringApplicationBuilder app = new SpringApplicationBuilder(SpringMongoConnectionViaPropertiesApp.class)
.properties(
"spring.data.mongodb.host=oldValue",
"spring.data.mongodb.port=oldValue",
"spring.data.mongodb.database=oldValue",
"spring.data.mongodb.username=oldValue",
"spring.data.mongodb.password=oldValue"
);
app.run();
assertInsertSucceeds(app.context());
}
由于系统属性优先级更高,属性文件中的旧值不会影响应用。当需要使用新连接详情重启应用而不修改代码时,此方法很有用。
3.3. 使用连接URI属性
也可以用单个属性替代主机、端口等独立属性:
spring.data.mongodb.uri="mongodb://admin:password@localhost:27017/baeldung"
此属性包含初始属性的所有值,无需单独指定五个属性。基本格式如下:
mongodb://<username>:<password>@<host>:<port>/<database>
URI中的database部分更准确地说是默认认证数据库。最重要的是,spring.data.mongodb.uri不能与主机、端口和凭据等独立属性同时指定,否则运行应用时会报错:
@Test
public void givenConnectionUri_whenAlsoIncludingIndividualParameters_thenInvalidConfig() {
System.setProperty(
"spring.data.mongodb.uri",
"mongodb://" + USER + ":" + PASS + "@" + HOST + ":" + PORT + "/" + DB
);
SpringApplicationBuilder app = new SpringApplicationBuilder(SpringMongoConnectionViaPropertiesApp.class)
.properties(
"spring.data.mongodb.host=" + HOST,
"spring.data.mongodb.port=" + PORT,
"spring.data.mongodb.username=" + USER,
"spring.data.mongodb.password=" + PASS
);
BeanCreationException e = assertThrows(BeanCreationException.class, () -> {
app.run();
});
Throwable rootCause = e.getRootCause();
assertTrue(rootCause instanceof IllegalStateException);
assertThat(rootCause.getMessage()
.contains("Invalid mongo configuration, either uri or host/port/credentials/replicaSet must be specified"));
}
最终,此配置选项不仅更简洁,有时甚至是必需的。因为某些选项只能通过连接字符串设置,例如使用mongodb+srv连接副本集。因此后续示例将仅使用这个更简单的配置属性。
4. 使用MongoClient的Java配置
MongoClient表示与MongoDB数据库的连接,它总是在底层创建,但我们也可以编程式配置。虽然更冗长,但这种方法有几个优势。接下来几小节将探讨这些优势。
4.1. 通过AbstractMongoClientConfiguration连接
在第一个示例中,我们将扩展Spring Data MongoDB的AbstractMongoClientConfiguration类:
@SpringBootApplication
public class SpringMongoConnectionViaClientApp extends AbstractMongoClientConfiguration {
// main方法
}
接着注入所需属性:
@Value("${spring.data.mongodb.uri}")
private String uri;
@Value("${spring.data.mongodb.database}")
private String db;
说明:这些属性可以硬编码,也可以使用与Spring Data变量不同的名称。最重要的是,这次我们使用URI而非独立连接属性(两者不能混用)。因此不能重用之前的application.properties,需要将其移至其他位置。
AbstractMongoClientConfiguration要求重写getDatabaseName()方法,因为URI中不强制要求数据库名:
protected String getDatabaseName() {
return db;
}
此时,由于使用默认Spring Data变量,已能连接数据库。MongoDB会在数据库不存在时自动创建。测试如下:
@Test
public void whenClientConfig_thenInsertSucceeds() {
SpringApplicationBuilder app = new SpringApplicationBuilder(SpringMongoConnectionViaClientApp.class);
app.web(WebApplicationType.NONE)
.run(
"--spring.data.mongodb.uri=mongodb://" + USER + ":" + PASS + "@" + HOST + ":" + PORT + "/" + DB,
"--spring.data.mongodb.database=" + DB
);
assertInsertSucceeds(app.context());
}
最后,可以重写mongoClient()方法以获得优于常规配置的优势。此方法将使用URI变量构建MongoDB客户端,从而直接引用它。例如,这使我们能列出连接中所有可用数据库:
@Override
public MongoClient mongoClient() {
MongoClient client = MongoClients.create(uri);
ListDatabasesIterable<Document> databases = client.listDatabases();
databases.forEach(System.out::println);
return client;
}
当需要完全控制MongoDB客户端创建时,这种配置方式很有用。
4.2. 创建自定义MongoClientFactoryBean
下一个示例创建MongoClientFactoryBean。这次使用名为custom.uri的属性保存连接配置:
@SpringBootApplication
public class SpringMongoConnectionViaFactoryApp {
// main方法
@Bean
public MongoClientFactoryBean mongo(@Value("${custom.uri}") String uri) {
MongoClientFactoryBean mongo = new MongoClientFactoryBean();
ConnectionString conn = new ConnectionString(uri);
mongo.setConnectionString(conn);
MongoClient client = mongo.getObject();
client.listDatabaseNames()
.forEach(System.out::println);
return mongo;
}
}
此方法无需扩展AbstractMongoClientConfiguration,且能控制MongoClient的创建。例如,调用mongo.setSingleton(false)后,每次调用mongo.getObject()都会返回新客户端而非单例。
4.3. 使用MongoClientSettingsBuilderCustomizer设置连接详情
最后一个示例使用MongoClientSettingsBuilderCustomizer:
@SpringBootApplication
public class SpringMongoConnectionViaBuilderApp {
// main方法
@Bean
public MongoClientSettingsBuilderCustomizer customizer(@Value("${custom.uri}") String uri) {
ConnectionString connection = new ConnectionString(uri);
return settings -> settings.applyConnectionString(connection);
}
}
使用此类可自定义连接的某些部分,同时保持其余部分的自动配置。当需要以编程方式设置少量属性时,此方法特别有用。
5. 总结
本文探讨了Spring Data MongoDB提供的多种工具,并使用它们以不同方式创建连接。此外,我们构建了测试用例确保配置按预期工作,最后还了解了配置优先级如何影响连接属性。
完整源代码可在GitHub获取。