1. Introduction
1.绪论
In this tutorial, we’re going to see different ways to configure a connection to our database. We’ll use Spring Boot and Spring Data MongoDB. Exploring Spring’s flexible configuration, we’ll create a different application for each approach. As a result, we’ll be able to choose the most appropriate one.
在本教程中,我们将看到配置与数据库的连接的不同方法。我们将使用Spring Boot和Spring Data MongoDB。探索Spring的灵活配置,我们将为每种方法创建一个不同的应用程序。因此,我们将能够选择最合适的方式。
2. Testing Our Connections
2.测试我们的连接
Before we start building our applications, we’ll create a test class. Let’s start with a few constants we’ll reuse:
在我们开始构建我们的应用程序之前,我们将创建一个测试类。让我们从一些我们将重复使用的常量开始。
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
}
Our tests consist of running our application, then trying to insert a document in a collection called “items”. After inserting our document, we should receive an “_id” from our database, and we consider the test to be successful. Let’s create a helper method for that:
我们的测试包括运行我们的应用程序,然后尝试在一个名为“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);
}
Our method receives the Spring context from our application so that we can retrieve the MongoTemplate instance. After that, we build a simple JSON document from a string with Document.parse().
我们的方法从我们的应用程序中接收Spring上下文,以便我们能够检索MongoTemplate实例。之后,我们用Document.parse()从一个字符串建立一个简单的JSON文档。
This way, we don’t need to create a repository or a document class. Then, after inserting, we assert the properties in our inserted document are what we expect.
这样,我们就不需要创建一个资源库或一个文档类。然后,在插入之后,我们断言我们插入的文档中的属性是我们所期望的。
3. Minimal Setup via application.properties
3.通过application.properties进行最低限度的设置
Our first example is the most common way of configuring connections. We just have to provide our database information in our 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
All available properties reside in the MongoProperties class from Spring Boot. We can also use this class to check default values. We can define any configuration in our properties file via application arguments. We’ll see how this works in the following section.
所有可用的属性都位于Spring Boot的MongoProperties类中。我们还可以使用这个类来检查默认值。我们可以通过应用程序参数在我们的属性文件中定义任何配置。我们将在下一节看到这一点。
In our application class, we don’t need anything special to get up and running:
在我们的应用类中,我们不需要任何特别的东西来启动和运行。
@SpringBootApplication
public class SpringMongoConnectionViaPropertiesApp {
public static void main(String... args) {
SpringApplication.run(SpringMongoConnectionViaPropertiesApp.class, args);
}
}
This configuration is all we need to connect to our database instance. The @SpringBootApplication annotation includes @EnableAutoConfiguration. It takes care of discovering that our application is a MongoDB application based on our classpath.
该配置是我们连接到数据库实例所需的全部内容。@SpringBootApplication注解包括@EnableAutoConfiguration。它负责根据我们的classpath发现我们的应用程序是一个MongoDB应用程序。
To test it, we can use SpringApplicationBuilder to get a reference to the application context. Then, to assert our connection is valid, we use the assertInsertSucceeds method created earlier:
为了测试它,我们可以使用SpringApplicationBuilder来获得对应用程序上下文的引用。然后,为了断定我们的连接是有效的,我们使用之前创建的assertInsertSucceeds方法:。
@Test
public void whenPropertiesConfig_thenInsertSucceeds() {
SpringApplicationBuilder app = new SpringApplicationBuilder(SpringMongoConnectionViaPropertiesApp.class)
app.run();
assertInsertSucceeds(app.context());
}
In the end, our application successfully connected using our application.properties file.
最后,我们的应用程序使用我们的application.properties文件成功连接。
3.1. Overriding Properties With Command Line Arguments
3.1.用命令行参数重写属性
We can override our properties file when running our application with command line arguments. These are passed to the application when run with the java command, mvn command, or IDE configuration. The method to provide these will depend on the command we’re using.
我们可以在使用命令行参数运行应用程序时覆盖我们的属性文件。当使用java命令、mvn命令或IDE配置运行时,这些参数会传递给应用程序。提供这些的方法将取决于我们使用的命令。
Let’s see an example using mvn to run our Spring Boot application:
让我们看看一个例子使用mvn来运行我们的Spring Boot应用程序: 。
mvn spring-boot:run -Dspring-boot.run.arguments='--spring.data.mongodb.port=7017 --spring.data.mongodb.host=localhost'
To use it, we specify our properties as values to the spring-boot.run.arguments argument. We use the same property names but prefix them with two dashes. Since Spring Boot 2, multiple properties should be separated by a space. Finally, after running the command, there shouldn’t be errors.
为了使用它,我们把我们的属性作为spring-boot.run.arguments参数的值来指定。我们使用相同的属性名称,但在它们前面加上两个破折号。从Spring Boot 2开始,多个属性应该用空格隔开。最后,运行命令后,不应该有错误。
Options configured this way always have precedence over the properties file. This option is useful when we need to change our application parameters without changing our properties file. For instance, if our credentials have changed and we can’t connect anymore.
以这种方式配置的选项总是优先于属性文件。当我们需要在不改变属性文件的情况下改变我们的应用程序参数时,这个选项很有用。例如,如果我们的证书发生了变化,我们不能再连接。
To simulate this in our tests, we can set system properties before running our application. Also, we can override our application.properties with the properties method:
为了在我们的测试中模拟这一点,我们可以在运行我们的应用程序之前设置系统属性。另外,我们可以用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());
}
As a result, the old values in our properties file won’t affect our application because system properties have more precedence. This can be useful when we need to restart our application with new connection details without changing the code.
因此,我们的属性文件中的旧值将不会影响我们的应用程序,因为系统属性具有更高的优先权。当我们需要在不改变代码的情况下用新的连接细节重新启动我们的应用程序时,这可能很有用。
3.2. Using the Connection URI Property
3.2.使用连接URI属性
It’s also possible to use a single property instead of the individual host, port, etc.:
也可以用单个属性来代替单个主机、端口等。
spring.data.mongodb.uri="mongodb://admin:password@localhost:27017/baeldung"
This property includes all values from the initial properties, so we don’t need to specify all five. Let’s check the basic format:
该属性包括初始属性的所有值,所以我们不需要指定所有五个值。让我们检查一下基本格式。
mongodb://<username>:<password>@<host>:<port>/<database>
The database part in the URI is, more specifically, the default auth DB. Most importantly, the spring.data.mongodb.uri property cannot be specified along the individual ones for host, port, and credentials. Otherwise, we’ll get the following error when running our application:
URI 中的 database 部分,更确切地说,是 默认的 auth DB。最重要的是,spring.data.mongodb.uri属性不能与 host、port 和 credentials 的单独属性一起指定。否则,在运行我们的应用程序时,我们将得到以下错误。
@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"));
}
In the end, this configuration option is not only shorter but sometimes required. That’s because some options are only available through the connection string. For instance, using mongodb+srv to connect to a replica set. Therefore, we’ll use only this simpler configuration property for the next examples.
最后,这个配置选项不仅更短,而且有时是必需的。这是因为有些选项只能通过连接字符串获得。例如,使用mongodb+srv来连接到一个副本集。因此,在接下来的例子中,我们将只使用这个比较简单的配置属性。
4. Java Setup With MongoClient
4.使用MongoClient的Java设置
MongoClient represents our connection to a MongoDB database and is always created under the hood. But, we can also set it up programmatically. Despite being more verbose, this approach has a few advantages. Let’s take a look at them over the next sections.
MongoClient代表我们与 MongoDB 数据库的连接,并且总是在引擎盖下创建。但是,我们也可以通过编程来设置它。尽管这种方法更加繁琐,但它有一些优势。让我们在接下来的章节中了解一下这些优势。
4.1. Connecting via AbstractMongoClientConfiguration
4.1.通过AbstractMongoClientConfiguration进行连接
In our first example, we’ll extend the AbstractMongoClientConfiguration class from Spring Data MongoDB in our application class:
在我们的第一个示例中,我们将在应用类中扩展Spring Data MongoDB的AbstractMongoClientConfiguration类。
@SpringBootApplication
public class SpringMongoConnectionViaClientApp extends AbstractMongoClientConfiguration {
// main method
}
Next, let’s inject the properties we’ll need:
接下来,让我们注入我们将需要的属性。
@Value("${spring.data.mongodb.uri}")
private String uri;
@Value("${spring.data.mongodb.database}")
private String db;
To clarify, these properties could be hard-coded. Also, they could use names that differ from the expected Spring Data variables. Most importantly, this time, we’re using a URI instead of individual connection properties, which cannot be mixed. Consequently, we cannot reuse our application.properties for this application, and we should move it elsewhere.
澄清一下,这些属性可以是硬编码的。此外,它们可以使用与预期的 Spring Data 变量不同的名称。最重要的是,这次我们使用的是 URI,而不是单独的连接属性,后者不能混合使用。因此,我们不能将我们的 application.properties 重用于此应用程序,我们应该将其移至其他地方。
AbstractMongoClientConfiguration requires us to override getDatabaseName(). That’s because a database name is not required in a URI:
AbstractMongoClientConfiguration要求我们覆盖getDatabaseName()。这是因为URI中不需要数据库名称。
protected String getDatabaseName() {
return db;
}
At this point, because we’re using default Spring Data variables, we’d already be able to connect to our database. Also, MongoDB creates the database if it doesn’t exist. Let’s test it:
在这一点上,因为我们使用了默认的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());
}
Finally, we can override mongoClient() to get an advantage over conventional configuration. This method will use our URI variable to build a MongoDB client. That way, we can have a direct reference to it. For instance, this enables us to list all the databases available from our connection:
最后,我们可以覆盖mongoClient()以获得比传统配置更多的优势。该方法将使用我们的URI变量来构建MongoDB客户端。这样,我们就可以直接引用它。例如,这使我们能够列出我们连接中的所有可用数据库。
@Override
public MongoClient mongoClient() {
MongoClient client = MongoClients.create(uri);
ListDatabasesIterable<Document> databases = client.listDatabases();
databases.forEach(System.out::println);
return client;
}
Configuring connections this way is useful if we want complete control over the MongoDB client’s creation.
如果我们想完全控制MongoDB客户端的创建,这样配置连接是很有用的。
4.2. Creating a Custom MongoClientFactoryBean
4.2.创建一个自定义的MongoClientFactoryBean
In our next example, we’ll create a MongoClientFactoryBean. This time, we’ll create a property called custom.uri to hold our connection configuration:
在下一个示例中,我们将创建一个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;
}
}
With this approach, we don’t need to extend AbstractMongoClientConfiguration. Also, we have control over our MongoClient‘s creation. For instance, by calling mongo.setSingleton(false), we get a new client every time we call mongo.getObject(), instead of a singleton.
通过这种方法,我们不需要扩展AbstractMongoClientConfiguration。同时,我们可以控制MongoClient的创建。例如,通过调用mongo.setSingleton(false),我们在每次调用mongo.getObject()时都会得到一个新的客户端,而不是一个单子。
4.3. Set Connection Details With MongoClientSettingsBuilderCustomizer
4.3.用MongoClientSettingsBuilderCustomizer设置连接细节
In our last example, we’re going to use a 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);
}
}
We use this class to customize parts of our connection but still have auto-configuration for the rest. Helpful when we need to set just a few properties programmatically.
我们使用这个类来定制我们连接的部分内容,但其余部分仍有自动配置。当我们需要以编程方式设置一些属性时,这很有帮助。
5. Conclusion
5.总结
In this article, we saw the different tools brought by Spring Data MongoDB. We used them to create connections in different ways. Moreover, we built test cases to guarantee our configurations worked as intended. Meanwhile, we saw how configuration precedence could affect our connection properties.
在这篇文章中,我们看到了Spring Data MongoDB所带来的不同工具。我们使用它们以不同的方式创建连接。此外,我们还建立了测试用例,以保证我们的配置能按预期工作。同时,我们看到了配置优先级如何影响我们的连接属性。
And as always, the source code is available over on GitHub.
一如既往,源代码可在GitHub上获得。