今天部署了一个最简单的 Spring Boot 项目,但是执行 curl localhost:9090/health 一直返回 500。报错信息和 RabbitMQ 有关,可项目里根本没有用到 RabbitMQ。

{
    "status": 500,
    "error": "Internal Server Error",
    "exception": "java.lang.NoSuchMethodError",
    "message": "com.rabbitmq.client.ConnectionFactory.newConnection(Ljava/util/concurrent/ExecutorService;[Lcom/rabbitmq/client/Address;Ljava/lang/String;)Lcom/rabbitmq/client/Connection;",
    "path": "/health"
}

第一反应是依赖出了问题。NoSuchMethodError 表示运行时加载到的类里,没有调用方需要的方法。这和类完全找不到不一样,通常要检查依赖版本是否匹配。

先看依赖树

虽然没有主动使用 RabbitMQ,但其他依赖可能把它带进来。先查看 Maven 依赖:

mvn dependency:tree | grep rabbitmq

果然找到了相关依赖:

[INFO] |  +- com.rabbitmq:amqp-client:jar:3.5.7:compile
[INFO] |  |  +- com.rabbitmq:http-client:jar:1.1.1.RELEASE:compile

再看完整的依赖树,确认它们是从哪个依赖引入的:

mvn dependency:tree

只用 grep 能快速找到相关包,但会漏掉上面的依赖路径。

异常里调用的是带 ExecutorService、Address[] 和 String 三个参数的 newConnection()。而 amqp-client 3.5.7 中没有这个重载,运行时调用就会报错。

去掉不需要的依赖

Spring Boot 的自动配置会根据类路径和 Bean 等条件配置组件。项目没有写 RabbitMQ 的业务代码,不代表相关自动配置不会生效。满足条件后,Actuator 的 RabbitMQ 健康检查也会在访问 /health 时执行。

这个项目确实不需要 RabbitMQ,所以在引入它的那个 <dependency> 中加上排除项:

<exclusions>
    <exclusion>
        <groupId>com.rabbitmq</groupId>
        <artifactId>amqp-client</artifactId>
    </exclusion>
    <exclusion>
        <groupId>org.springframework.amqp</groupId>
        <artifactId>spring-rabbit</artifactId>
    </exclusion>
</exclusions>

如果有多个依赖路径引入这些包,需要分别处理。修改后再检查一次依赖树,重新打包并部署,避免还在运行原来的包。

再次访问 /health,状态恢复为 UP:

{
    "status": "UP",
    "diskSpace": {
        "status": "UP"
    }
}

这里省略了磁盘容量等字段。哈哈,确实是个最简单的项目,却被间接依赖带出了问题。

最后修改:2017 年 12 月 03 日
如果觉得我的文章对你有用,请随意赞赏