Spring Boot Starter-Web 尝试在启动时连接到 Mongo

Posted

技术标签:

【中文标题】Spring Boot Starter-Web 尝试在启动时连接到 Mongo【英文标题】:Spring Boot Starter-Web tries to connect to Mongo at startup 【发布时间】:2017-04-06 07:45:09 【问题描述】:

我在使用 Spring Boot 和 MongoDB 外部驱动程序时遇到了一些问题。我不能使用项目 Spring Data MongoDB,因为我需要使用 Mongo 提供的 ufficial async 驱动程序。但是,我需要使用 Spring Boot,因为我正在开发的模块是使用这个库的更大项目的一部分。

这是我的pom.xml 文件。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <artifactId>tx-view</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- omissis -->

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>mongodb-driver-async</artifactId>
            <version>$mongodb.version</version>
        </dependency>
     </dependencies>

    <build>
        <plugins>
            <plugin>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

详细来说,我使用的是 Spring Boot 1.4.1 和 Mongo Async Driver 3.2.2。

这是我的申请。

@SpringBootApplication(exclude = MongoAutoConfiguration.class, MongoDataAutoConfiguration.class)
public class TxViewApplication 
    public static void main(String[] args) 
        SpringApplication.run(TxViewApplication.class, args);
    

    @Value("$mongo.uri")
    private String mongoUri;

    @Bean
    public MongoClient mongoClient() 
        return MongoClients.create(mongoUri);
    

它遵循我目前唯一的(空)测试。

@SpringBootTest
@RunWith(SpringRunner.class)
public class ApplicationTest 
    @Test
    public void loadContext() throws Exception 

我在这个项目中没有其他代码。当我运行测试时,出现以下错误:

2016-11-22 15:43:58.597  INFO 4572 --- [null'-db:27017] org.mongodb.driver.cluster               : Exception in monitor thread while connecting to server db:27017

com.mongodb.MongoException: java.io.IOException: Il computer remoto ha rifiutato la connessione di rete.

at com.mongodb.connection.InternalStreamConnection.open(InternalStreamConnection.java:125) ~[mongodb-driver-core-3.2.2.jar:na]
at com.mongodb.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:128) ~[mongodb-driver-core-3.2.2.jar:na]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_101]
Caused by: java.io.IOException: Il computer remoto ha rifiutato la connessione di rete.

at sun.nio.ch.Iocp.translateErrorToIOException(Iocp.java:309) ~[na:1.8.0_101]
at sun.nio.ch.Iocp.access$700(Iocp.java:46) ~[na:1.8.0_101]
at sun.nio.ch.Iocp$EventHandlerTask.run(Iocp.java:399) ~[na:1.8.0_101]
at sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:112) ~[na:1.8.0_101]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[na:1.8.0_101]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) ~[na:1.8.0_101]
... 1 common frames omitted

如您所见,我已在 SpringBootApplication 注释中正确插入 exclude 子句,以阻止 Spring Boot 尝试处理自己与 Mongo 的连接,正如 Mongo tries to connect automatically to port 27017(localhost) 中所建议的那样。

我也注意到在添加到spring-boot-starter-web的依赖的pom.xml之后开始出现错误。

如何禁止 Spring Boot 在启动时尝试自动连接到 Mongo? MongoDB驱动的同步版本也存在同样的问题。

--- 编辑---

我也尝试用这种方式围绕async.MongoClient 对象构建一个包装器:

public class MongoWrapper 
    private final MongoClient mongo;

    public MongoWrapper() 
        mongo = MongoClients.create();
    

    public MongoClient getMongo() 
        return mongo;
    

配置已相应更改。

@Bean
public MongoWrapper mongo() 
    return new MongoWrapper();

不幸的是,一切都没有改变。 Spring Boot 似乎也以这种方式拦截了MongoClient 对象:(

非常感谢。

【问题讨论】:

也许SpringBootTest 不使用TxViewApplication 作为上下文的来源,因为您在其他地方还有另一个@SpringBootConfiguration。如果排除了mongo,那为什么还要在同一个类中定义一个MongoClient呢? 我发布的代码是项目中唯一的代码。我将配置合并到启动应用程序的同一类中以显示更少的代码。您的意思是我没有在 Spring 配置中定义任何 MongoClient 类型的对象吗? @StephaneNic​​oll,您建议如何将 MongoDB 的异步 java 驱动程序与 Spring Boot 集成? 如果您排除自动配置,我们尝试在启动时连接是没有意义的。可以分享一下样品吗? @StephaneNic​​oll 我在GitHub 上分享了一个演示项目。 pom.xml 是使用 Spring Initializr 生成的。然后我将依赖项添加到 mongo 异步驱动程序。如果您尝试运行DemoApplicationTests,您将能够复制错误。非常感谢。 【参考方案1】:

这有助于我们禁用 MongoDB 的异步 java 驱动程序以使用默认配置:

@EnableAutoConfiguration(exclude = MongoReactiveAutoConfiguration.class)

【讨论】:

【参考方案2】:

您自己的配置中有一个 MongoClient bean,如果您排除了自动配置,这对我来说没有任何意义。

我已经在您自己的配置中注释掉了 @Bean 定义,现在没有尝试连接到 Mongo。我不确定我是否回答了您的问题,您可能正在寻找其他内容,但如果您不想使用 mongo,请不要在自己的配置中定义 MongoClient

【讨论】:

我确实想使用 Mongo!但我不希望 Spring Boot 为我处理与它的连接。那你是说我不能使用Spring依赖注入机制来构建MongoClient实例,而不需要Spring Boot拦截? Spring boot 什么都不做。您创建此 bean 定义的事实使其在启动时连接。 Spring Boot 对此完全不负责。 Mongo 驱动程序文档指出 MongoClient 的简单创建不会强制数据库连接。你怎么解释这个? 哦,如果 mongo 文档指出,那一定是 Spring Boot 的错?看调用栈,没有一个与 Spring 相关的元素。将您的 main 替换为以下代码,您将遇到异常:public static void main(String[] args) throws IOException MongoClient mongoClient = MongoClients.create(); System.in.read(); 我会尝试向 MongoDB 人员询问发生了什么事。非常感谢您的耐心。

以上是关于Spring Boot Starter-Web 尝试在启动时连接到 Mongo的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot Security - 如果用户未通过 Oauth2 进行身份验证,如何禁用对 swagger ui 页面的端点的访问

玩·聚Spring丨5-3/4第三期自驾最美17公里亲子尽享烂漫时光,纵情花谷奇缘尝遍豆腐村,嗨爆澜海温泉音乐美食节燃烧你的烦恼

Spring Boot 学习例子

Spring Boot 2Spring Boot CLI

为啥 Spring Boot 应用程序 pom 同时需要 spring-boot-starter-parent 和 spring-boot-starter-web?

《02.Spring Boot连载:Spring Boot实战.Spring Boot核心原理剖析》