一、简介
在本教程中,我们将看到配置与数据库的连接的不同方法。我们将使用Spring Boot 和Spring Data 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";
// test cases
}
我们的测试包括运行我们的应用程序,然后尝试在名为“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 文档。
这样,我们就不需要创建存储库或文档类。然后,在插入之后,我们断言插入文档中的属性是我们所期望的。
3. 通过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
类中。我们也可以使用这个类来检查默认值。我们可以通过应用程序参数在属性文件中定义任何配置。我们将在下一节中看到它是如何工作的。
在我们的应用程序类中,我们不需要任何特殊的东西来启动和运行:
@SpringBootApplication
public class SpringMongoConnectionViaPropertiesApp {
public static void main(String... args) {
SpringApplication.run(SpringMongoConnectionViaPropertiesApp.class, args);
}
}
这个配置是我们连接到我们的数据库实例所需的全部。 @SpringBootApplication
注释包括@EnableAutoConfiguration
。它负责发现我们的应用程序是基于我们的类路径的MongoDB 应用程序。
为了测试它,我们可以使用SpringApplicationBuilder to
获取对应用程序上下文的引用。然后,为了断言我们的连接是有效的,我们使用之前创建的assertInsertSucceeds
方法:
@Test
public void whenPropertiesConfig_thenInsertSucceeds() {
SpringApplicationBuilder app = new SpringApplicationBuilder(SpringMongoConnectionViaPropertiesApp.class)
app.run();
assertInsertSucceeds(app.context());
}
最后,我们的应用程序使用我们的application.properties
文件成功连接。
3.1。使用命令行参数覆盖属性
当使用命令行参数运行我们的应用程序时,我们可以覆盖我们的属性文件。当使用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.2.使用连接URI 属性
也可以使用单个属性而不是单个主机、端口等:
spring.data.mongodb.uri="mongodb://admin:[email protected]:27017/baeldung"
此属性包括初始属性中的所有值,因此我们不需要指定所有五个。让我们检查一下基本格式:
mongodb://<username>:<password>@<host>:<port>/<database>
更具体地说,URI 中的database
部分是默认的auth DB。最重要的是,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 method
}
接下来,让我们注入我们需要的属性:
@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 method
@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 method
@Bean
public MongoClientSettingsBuilderCustomizer customizer(@Value("${custom.uri}") String uri) {
ConnectionString connection = new ConnectionString(uri);
return settings -> settings.applyConnectionString(connection);
}
}
我们使用这个类来自定义连接的部分,但仍然有其余部分的自动配置。当我们需要以编程方式设置几个属性时很有帮助。
5. 结论
在本文中,我们看到了Spring Data MongoDB 带来的不同工具。我们使用它们以不同的方式创建连接。此外,我们构建了测试用例以确保我们的配置按预期工作。同时,我们看到了配置优先级如何影响我们的连接属性。
0 评论