[spring-projects/spring-boot]当 spring.data.mongodb.uri 设置时,Spring Data MongoDB 的自动配置会忽略 spring.data.mongodb.database

2024-05-08 581 views
3

升级到 spring-boot 3 后,使用连接字符串时,mongo 自动配置不起作用。

我认为如果为空,我们需要有一个后备选项this.connectionDetails.getConnectionString().getDatabase()

@Bean
@ConditionalOnMissingBean(ReactiveMongoDatabaseFactory.class)
public SimpleReactiveMongoDatabaseFactory reactiveMongoDatabaseFactory(MongoClient mongo) {
    return new SimpleReactiveMongoDatabaseFactory(mongo,
            this.connectionDetails.getConnectionString().getDatabase());
}

我们可以将上面的代码更改为下面提到的吗?

@Bean
@ConditionalOnMissingBean(ReactiveMongoDatabaseFactory.class)
public SimpleReactiveMongoDatabaseFactory reactiveMongoDatabaseFactory(MongoProperties properties,         MongoClient mongo) {
        String database = this.connectionDetails.getConnectionString().getDatabase();
        if(database==null)
            database = properties.getDatabase()
        return new SimpleReactiveMongoDatabaseFactory(mongo,
            database);
}

回答

0

感谢您的报告。我认为我们无法进行建议的更改,因为目的是连接详细信息包含连接到 Mongo 所需的所有信息。您能退一步描述一下您面临的问题吗?一个适用于 3.0.x 但不适用于 3.1.0 的示例将是理想的。

6

我们对 mongoDB Atlas 的 uri 也有同样的问题: spring.data.mongodb.uri=mongodb+srv://user:pwd@example-domain.f5t41.mongodb.net/?retryWrites=true&w=majority

Caused by: java.lang.IllegalArgumentException: Database name must not be empty

ConnectionString尝试按照以下格式解析 URI: mongodb+srv://[username:password@]host[/[database][?options]]

从 mongo 文档看来该[database]参数是可选的。

编辑:这是否是一个需要向 Atlas 团队报告的问题?

9

@burl21我不确定这是同一个问题。此处报告的问题特定于 Spring Boot 3.1,但对于您的问题,spring.data.mongodb.uri我也看到 Spring Boot 3.0.x 出现故障:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.mongodb.core.MongoDatabaseFactorySupport]: Factory method 'mongoDatabaseFactory' threw exception with message: Database name must not be empty
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:171) ~[spring-beans-6.0.8.jar:6.0.8]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:655) ~[spring-beans-6.0.8.jar:6.0.8]
    ... 61 common frames omitted
Caused by: java.lang.IllegalArgumentException: Database name must not be empty
    at org.springframework.util.Assert.hasText(Assert.java:294) ~[spring-core-6.0.8.jar:6.0.8]
    at org.springframework.data.mongodb.core.MongoDatabaseFactorySupport.<init>(MongoDatabaseFactorySupport.java:68) ~[spring-data-mongodb-4.0.5.jar:4.0.5]
    at org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory.<init>(SimpleMongoClientDatabaseFactory.java:75) ~[spring-data-mongodb-4.0.5.jar:4.0.5]
    at org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory.<init>(SimpleMongoClientDatabaseFactory.java:64) ~[spring-data-mongodb-4.0.5.jar:4.0.5]
    at org.springframework.boot.autoconfigure.data.mongo.MongoDatabaseFactoryConfiguration.mongoDatabaseFactory(MongoDatabaseFactoryConfiguration.java:43) ~[main/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:139) ~[spring-beans-6.0.8.jar:6.0.8]
    ... 62 common frames omitted

如果您希望我们调查此问题,请打开一个单独的问题,因为很难跟踪同一问题中的两个可能不同的问题。

8

@burl21我不确定这是同一个问题。此处报告的问题特定于 Spring Boot 3.1,但对于您的问题,spring.data.mongodb.uri我也看到 Spring Boot 3.0.x 出现故障:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.mongodb.core.MongoDatabaseFactorySupport]: Factory method 'mongoDatabaseFactory' threw exception with message: Database name must not be empty
  at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:171) ~[spring-beans-6.0.8.jar:6.0.8]
  at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:655) ~[spring-beans-6.0.8.jar:6.0.8]
  ... 61 common frames omitted
Caused by: java.lang.IllegalArgumentException: Database name must not be empty
  at org.springframework.util.Assert.hasText(Assert.java:294) ~[spring-core-6.0.8.jar:6.0.8]
  at org.springframework.data.mongodb.core.MongoDatabaseFactorySupport.<init>(MongoDatabaseFactorySupport.java:68) ~[spring-data-mongodb-4.0.5.jar:4.0.5]
  at org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory.<init>(SimpleMongoClientDatabaseFactory.java:75) ~[spring-data-mongodb-4.0.5.jar:4.0.5]
  at org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory.<init>(SimpleMongoClientDatabaseFactory.java:64) ~[spring-data-mongodb-4.0.5.jar:4.0.5]
  at org.springframework.boot.autoconfigure.data.mongo.MongoDatabaseFactoryConfiguration.mongoDatabaseFactory(MongoDatabaseFactoryConfiguration.java:43) ~[main/:na]
  at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
  at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
  at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
  at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
  at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:139) ~[spring-beans-6.0.8.jar:6.0.8]
  ... 62 common frames omitted

如果您希望我们调查此问题,请打开一个单独的问题,因为很难跟踪同一问题中的两个可能不同的问题。

感谢您检查。是的,从 3.0.x 开始它就失败了。正如您已经确认的问题一样,我只是直接提到了 Spring Boot 2.6.6 代码中的逻辑。正如您所看到的,properties.getMongoClientDatabase() 方法从"spring.data.mogodb.uri"返回数据库名称。如果它在 uri 中不可用,则会回退到数据库属性 "spring.data.mongodb.database"。因此,我期望 3.xx 中也有相同的行为。

public class MongoReactiveDataAutoConfiguration {
       ...
    @Bean
    @ConditionalOnMissingBean(ReactiveMongoDatabaseFactory.class)
    public SimpleReactiveMongoDatabaseFactory reactiveMongoDatabaseFactory(MongoProperties properties,
            MongoClient mongo) {
        String database = properties.getMongoClientDatabase();
        return new SimpleReactiveMongoDatabaseFactory(mongo, database);
    }
    ...
}
1

是的,从 3.0.x 开始就失败了

抱歉,我现在很困惑,因为问题标题说“升级到 3.1.x 后”。你能澄清一下吗?

5

是的,从 3.0.x 开始就失败了

抱歉,我现在很困惑,因为问题标题说“升级到 3.1.x 后”。你能澄清一下吗?

抱歉,我直接从 2.x 升级到 3.1 因此标题。我现在改了标题。

2

我尝试使用 Spring Boot 3.0.7 重现该问题。我没有看到这个错误。我已在此处附上演示代码。 Spring Boot 3.0.7 在这里工作正常

当我将 spring boot 版本更改为 3.1.1-SNAPSHOT 时,我看到了失败。

spring boot 3.1.1-SNAPSHOT在这里失败。

6

晚上好,

将 spring-boot-starter-parent 从 3.0.1 更新到 3.1.0 后,我遇到了同样的错误。

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.mongodb.core.MongoDatabaseFactorySupport]: Factory method 'mongoDatabaseFactory' threw exception with message: Database name must not be empty
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:171)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:655)
    ... 96 more
Caused by: java.lang.IllegalArgumentException: Database name must not be empty
    at org.springframework.util.Assert.hasText(Assert.java:294)
    at org.springframework.data.mongodb.core.MongoDatabaseFactorySupport.<init>(MongoDatabaseFactorySupport.java:68)
    at org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory.<init>(SimpleMongoClientDatabaseFactory.java:75)
    at org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory.<init>(SimpleMongoClientDatabaseFactory.java:64)
    at org.springframework.boot.autoconfigure.data.mongo.MongoDatabaseFactoryConfiguration.mongoDatabaseFactory(MongoDatabaseFactoryConfiguration.java:47)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:139)
    ... 97 more

存储库的链接是https://github.com/LauroSilveira/alura-flix-api。请问您能检查一下这个错误吗?

亲切的问候, 劳罗·科雷亚

3

如果添加上下文,My DB SaaS 提供商不会提供包含数据库名称的连接字符串,而是用于实例。人们可以摆弄连接字符串,添加数据库名称......这绕过了连接字符串始终包含数据库名称的假设。

对我来说,重写 PropertiesMongoConnectionDetails 似乎是最简单的地方。

  @Bean
  PropertiesMongoConnectionDetails mongoProperties(final MongoProperties mongoProperties) {
    final String withDatabaseName =
        mongoProperties.getUri().replace("/?", "/" + mongoProperties.getDatabase() + "?");
    mongoProperties.setUri(withDatabaseName);

    return new PropertiesMongoConnectionDetails(mongoProperties);
  }
1

如果添加上下文,My DB SaaS 提供商不会提供包含数据库名称的连接字符串,而是用于实例。人们可以摆弄连接字符串,添加数据库名称......这绕过了连接字符串始终包含数据库名称的假设。

对我来说,重写 PropertiesMongoConnectionDetails 似乎是最简单的地方。

  @Bean
  PropertiesMongoConnectionDetails mongoProperties(final MongoProperties mongoProperties) {
    final String withDatabaseName =
        mongoProperties.getUri().replace("/?", "/" + mongoProperties.getDatabase() + "?");
    mongoProperties.setUri(withDatabaseName);

    return new PropertiesMongoConnectionDetails(mongoProperties);
  }

@carldini 这应该适用于你的情况。但是,我认为我们不应该以编程方式更改configurationProperty bean 的值。也许,您可以创建 MongoProperties 的新对象并传递新的 obj 。

3

谢谢大家。我现在明白了这个问题。

spring.data.mongodb.uri属性始终被记录为覆盖数据库:

Mongo 数据库 URI。覆盖主机、端口、用户名、密码和数据库。

在 3.1 之前,实现与以前的实现不一致,这就是它以前工作的原因。该行为现在与文档一致,因此spring.data.mongodb.database如果您设置了 ,则该行为将被忽略spring.data.mongodb.uri。我们现在可能需要将其回滚,并花更多时间在 Spring Boot 3.2 中解决问题。

同时,定义您自己的 bean 可能是最简单SimpleReactiveMongoDatabaseFactorySimpleMongoClientDatabaseFactory。像这样的事情:

@Bean
MongoDatabaseFactorySupport<?> mongoDatabaseFactory(MongoClient mongoClient, MongoProperties properties) {
    return new SimpleMongoClientDatabaseFactory(mongoClient, properties.getDatabase());
}
7

我认为我们无法进行建议的更改,因为目的是连接详细信息包含连接到 Mongo 所需的所有信息。

我想我正在改变主意。连接详细信息已经足以进行连接。只有 Spring Data Mongo 坚持使用最终用于调用com.mongodb.client.MongoClient.getDatabase(String).这可能与用于身份验证的连接字符串中的数据库完全分开。

4

你好,

如果它可以帮助任何也面临这个问题的人。在从 3.0.x 更新到 3.1.x 后的项目中,我通过使用属性覆盖解决了该问题:替换:

spring.data.mongodb.database=demo-db
spring.data.mongodb.uri=mongodb://localhost:27018/?readPreference=primaryPreferred&directConnection=true

有了这个 :

spring.data.mongodb.database=demo-db
spring.data.mongodb.uri=mongodb://localhost:27018/${spring.data.mongodb.database}?readPreference=primaryPreferred&directConnection=true

如果您需要在 URI 中进行身份验证,您还需要在 URI 中添加身份验证数据库:

spring.data.mongodb.authentication-database=admin
spring.data.mongodb.database=demo-db
spring.data.mongodb.uri=mongodb://username:password@localhost:27018/${spring.data.mongodb.database}?authSource=${spring.data.mongodb.authentication-database}&readPreference=primaryPreferred&directConnection=true

我的项目使用 Yaml 文件而不是属性文件,但我希望无论如何行为都是相同的。

此致

7

只是一个简单的问题:我在 3.1.0 上遇到的是该属性spring.data.mongodb.authentication-database被忽略,即使spring.data.mongodb.uri没有设置。这也包含在修复范围内吗?

9

@ctonsing 如果不了解更多,很难说。请尝试 3.1.1-SNAPSHOT (可从https://repo.spring.io/snapshot获取)并查看您的问题是否已解决。如果不是,请使用重现该问题的最小示例打开一个新问题。

9

谢谢@wilkinsona,我按照建议做了,问题已在当前的 3.1.1-SNAPSHOT 中修复。感谢所有开发人员的辛勤工作!

3

感谢您尝试快照,@ctonsing。非常感激。