最后更新:2026-10-28
适用场景:Spring Boot 3.x、构造器注入、NoSuchBeanDefinitionException
启动时报 required a bean of type ... that could not be found,看到类明明就在项目里,却注入不进来。先把“Java 类存在”和“Spring 容器里有这个 Bean”分开。编译器能找到类,只说明它在 classpath;Spring 还得扫描到、创建成功,并且类型匹配。
先读错误里真正缺的类型
不要只看最上面的 UnsatisfiedDependencyException。往下找 No qualifying bean of type '...' available,记下完整包名与注入点。比如缺的是 com.example.order.PayService,就去查这个接口的实现,而不是看到 OrderController 启动失败便去改 Controller。
一个常见的正常结构是:
com.example.app
├── DemoApplication.java // @SpringBootApplication
├── controller
│ └── OrderController.java
└── service
└── PayServiceImpl.java // @Service
启动类放在业务包的上层,组件扫描才能覆盖子包。若启动类在 com.example.app.web,而 Service 在平级的 com.example.app.service,默认扫描范围就可能漏掉它。优先调整包结构;确需跨模块扫描时,再用明确的 scanBasePackageClasses,不要粗暴扫描整个 com。这是 Spring Boot 官方推荐的包布局。
类被扫到了吗?它是 Spring 管理的吗?
接口本身不会因为存在就自动成为 Bean。实现类要通过 @Service / @Component 等方式被扫描,或由配置类的 @Bean 方法返回。例如:
public interface PayService {
void pay(long orderId);
}
@Service
public class PayServiceImpl implements PayService {
@Override
public void pay(long orderId) {
// 支付逻辑
}
}
两个类型分别放在自己的 Java 文件里。注入时优先用接口类型:
@RestController
public class OrderController {
private final PayService payService;
public OrderController(PayService payService) {
this.payService = payService;
}
}
只有一个构造器时,Spring 不要求再写 @Autowired。反过来,自己 new OrderController(...) 或 new PayServiceImpl() 得到的对象不由容器管理;这种情况通常表现为字段没注入或代理能力缺失,不要和“启动时找不到 Bean”混为一谈。Spring 的构造器注入文档有详细说明。
有注解仍然没有 Bean:查条件与环境
实现类若标了 @Profile("prod"),而当前跑的是 dev,它不会注册。@ConditionalOnProperty、@ConditionalOnClass 以及某些 Starter 的自动配置也会让 Bean 只在条件满足时出现。此时应查看当前激活的 profile、实际配置值和依赖树,不要单纯追加一个 @Component。
改完配置文件但只重启旧 Jar,也会让人误以为 Spring 忽略了注解。先确认部署的构建产物,再追条件配置。多环境配置可以对照Spring Boot 配置文件怎么写。
如果缺的是 MyBatis Mapper,检查 @Mapper / @MapperScan、Mapper 所在包和 MyBatis Starter;如果缺的是 Repository,还要看对应数据访问模块的启用范围。它们不是普通 @Service 实现类,处理方式要按各自框架来。Spring Boot 整合 MyBatis可以接着核对。
别把“找不到”和“找到太多”当成一回事
NoSuchBeanDefinitionException 是候选 Bean 不足;NoUniqueBeanDefinitionException 则是同一类型有多个候选。假如同时有 WechatPayService 和 AlipayPayService 实现 PayService,要根据业务选择 @Qualifier,或在确有默认实现时使用 @Primary。随手删掉一个实现、把注入改成 Object,只是把问题藏起来。Spring 的限定符说明给出了选择规则。
排查顺序很简单:先读完整缺失类型,再查启动类包位置、实现类注册方式、条件配置,最后看是不是多实现冲突。每改一处就重新启动一次,确认异常链里缺失的类型是否变化,别同时改扫描路径和注入方式,最后不知道哪步起了作用。
参考资料
Spring Boot 3.5:Structuring Your Code
Spring Framework 6.2:Using @Autowired
Spring Framework 6.2:Autowiring Qualifiers
更新记录
2026-10-28:创建文章,补充包扫描、条件注册与多实现的分流排查。
Spring Boot 找不到 Bean 怎么排查
https://java.li/archives/spring-boot-no-such-bean
评论