把
spring-ai-openai-spring-boot-starter和spring-boot-starter-webflux放一个项目,启动大概率报No qualifying bean of type 'RestClient.Builder'。根因是早期 OpenAI 自动配置写死了要注入RestClient.Builder,而 WebFlux 只给WebClient.Builder。这是 1.0.0-M1 到 M3 的老 bug,1.0.0 GA 已修;卡在 M 版就临时补一个 RestClient 的 Bean。
Issue & Env(案发现场与环境)
- 业务场景:用 WebFlux(reactive 栈)搭的项目,想接入 Spring AI 的 OpenAI 模型。
- 环境:Spring AI 1.0.0-M1~M3(bug 区间),Spring Boot 3.3.4,Java 17。1.0.0 GA 之后已修复。
StackTrace(堆栈日志)
启动报:
APPLICATION FAILED TO START
Description:
Parameter 2 of method openAiChatModel in org.springframework.ai.autoconfigure.openai.OpenAiAutoConfiguration required a bean of type 'org.springframework.web.client.RestClient$Builder' that could not be found.
Action:
Consider defining a bean of type 'org.springframework.web.client.RestClient$Builder' in your configuration.
底层异常链的完整堆栈,顶层是启动时构造 Bean 失败的 UnsatisfiedDependencyException,根因是找不到 RestClient.Builder:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'openAiChatModel' defined in class path resource [org/springframework/ai/autoconfigure/openai/OpenAiAutoConfiguration.class]: Unsatisfied dependency expressed through method 'openAiChatModel' parameter 2: No qualifying bean of type 'org.springframework.web.client.RestClient$Builder' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:795)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:542)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1355)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1185)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1217)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:962)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.web.client.RestClient$Builder' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1512)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1432)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:908)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:793)
Reproduce(复现代码)
两个依赖单独存进 WebFlux 项目就能稳定复现:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
配好 spring.ai.openai.api-key 后启动,直接报上面的 RestClient.Builder 缺失。
Root Cause(根因分析)
自动配置里 openAiChatModel(...) 的第 3 个参数(parameter 2)写死了 RestClient.Builder。构造 Bean 时从容器找这个类型的 Bean,WebFlux 项目里没有,直接 UnsatisfiedDependencyException。RestClient 是 Spring MVC(servlet 栈)的 HTTP 客户端;WebFlux 项目只自动配置 WebClient 和 WebClient.Builder,不注册 RestClient.Builder。
维护者在 issue 里把取舍说清了。markpollack 试过直接给 spring-ai-openai 拉 spring-boot-starter-web,能顺带把 RestClient.Builder 配置出来,但会把 Tomcat、spring-webmvc 全拖进来,控制台应用不想要。wilkinsona 给的方向:依赖只加 spring-web,注入点改用 ObjectProvider,用 AnyNestedCondition 判断「有 RestClient.Builder 或有 WebClient.Builder」二选一即可。这个方向最终落在 PR #1550,有人在 1.0.0-SNAPSHOT 上验证过已恢复。
The Fix(解决方案)
正解:升级到 Spring AI 1.0.0 GA 或更高
1.0.0 起自动配置在 servlet、reactive 两种栈下都能正确装配。用 BOM 管版本:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
再把 starter 换成对应版本的标准命名,比如 spring-ai-starter-model-openai。
卡在 M 版的临时绕过
没法升级时,补一个 RestClient.Builder Bean 就能让自动配置过:
@Bean
RestClient.Builder restClientBuilder() {
return RestClient.builder();
}
或者给 spring-ai-openai 拉一个 spring-web 依赖,让 RestClient 自动配置生效。别用 spring-boot-starter-web 去解,它会把整套 servlet 栈带进来,reactive 项目不划算。
