今天部署了一个最简单的 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"
}
}这里省略了磁盘容量等字段。哈哈,确实是个最简单的项目,却被间接依赖带出了问题。