Spring Data MongoDB – 配置連接
一、簡介
在本教程中,我們將看到配置與數據庫的連接的不同方法。我們將使用 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 帶來的不同工具。我們使用它們以不同的方式創建連接。此外,我們構建了測試用例以確保我們的配置按預期工作。同時,我們看到了配置優先級如何影響我們的連接屬性。
與往常一樣,源代碼可在 GitHub 上獲得。