Spring Bean扫描

好的,没有问题。基于我们之前讨论的内容,这是一篇关于 Spring Bean 扫描问题的深度解析博客。


Spring Bean扫描

作者:Gz | 发布时间:2025年9月9日

🎯 Spring如何找到你的Bean?

首先要理解原理。Spring的组件扫描主要依赖于@ComponentScan注解。

在现代Spring Boot应用中,你通常看不到@ComponentScan,因为它已经被包含在了@SpringBootApplication注解中。

@SpringBootApplication // <-- 这个注解里面其实包含了 @ComponentScan
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}
}

默认情况下,@SpringBootApplication会扫描其所在包以及所有子包下的所有组件。
在这里插入图片描述
例如直接把图片中的dao软件包移动到itheima下面,然后启动程序就会出现扫描不到错误
在这里插入图片描述
在对应类没有加注解也会出现报错
在这里插入图片描述
在这里插入图片描述

com.example.myapp      <-- 启动类所在的根包
├── MyApplication.java   <-- @SpringBootApplication 在这里
├── controller
│   └── UserController.java  (@RestController)
├── service
│   └── UserServiceImpl.java (@Service)
└── repository└── UserRepositoryImpl.java (@Repository)

在这个结构下,controller, service, repository 都是根包 com.example.myapp 的子包,所以它们的组件都能被自动发现。

🔍 常见问题与解决方案

问题一:NoSuchBeanDefinitionException - “我的Bean去哪了?”

这是最常见的错误,意味着Spring在需要注入一个Bean时,在容器里找不到它。

原因1:忘记添加组件注解

这是最粗心也最常见的错误。你创建了一个类,但忘记用@Component, @Service, @Repository, @Controller等注解标记它。

解决方案:检查你的类,确保它有相应的组件注解。

// ❌ 错误:这个类不会被Spring发现
public class UserServiceImpl implements UserService { ... }// ✅ 正确:添加@Service注解
@Service
public class UserServiceImpl implements UserService { ... }
原因2:组件不在默认的扫描路径下

这是初学者最容易犯的错误。你的组件类所在的包,不是启动类所在包的子包。

示例:错误的包结构

com
├── example
│   └── myapp            <-- 启动类在这里
│       └── MyApplication.java
└── other└── utils            <-- 工具类想被注入,但它不在扫描路径下└── MyUtil.java (@Component)

解决方案A (推荐)遵循规范,将包移动到启动类所在包的子包下。这是最符合Spring Boot“约定优于配置”思想的做法。

解决方案B (特殊情况使用):在启动类上显式指定要扫描的包

@SpringBootApplication
@ComponentScan(basePackages = {"com.example.myapp", "com.other.utils"})
public class MyApplication { ... }

问题二:NoUniqueBeanDefinitionException - “Bean太多了,我该选哪个?”

这个错误与找不到Bean正好相反:Spring找到了多个符合注入要求的Bean,导致它不知道该注入哪一个。

原因:一个接口有多个实现类

假设我们有一个NotificationService接口,同时有两个实现:EmailServiceSmsService

public interface NotificationService {void send(String message);
}@Service("emailNotification")
public class EmailService implements NotificationService { ... }@Service("smsNotification")
public class SmsService implements NotificationService { ... }

当你尝试注入时,就会出现问题:

@Autowired
private NotificationService notificationService; // <-- Spring懵了:你想要Email还是SMS?

** 🎯:@Primary指定首选项**
给其中一个实现类加上@Primary注解,告诉Spring如果遇到多个选项,优先注入这一个。

@Service("emailNotification")
@Primary // <-- 默认情况下,注入这一个
public class EmailService implements NotificationService { ... }

解决方案B:使用@Qualifier精确指定
在注入点使用@Qualifier注解,通过Bean的名称来精确指定你想要注入哪一个实现。

@Autowired
@Qualifier("smsNotification") // <-- 我明确想要注入名为 "smsNotification" 的Bean
private NotificationService notificationService;

🎯 @Resource注解总结

📋 @Resource 是什么?

@ResourceJava标准注解(JSR-250规范),用于依赖注入,由Java EE提供,不是Spring特有的。

@Resource
private UserDao userDao;  // 按类型注入@Resource(name = "userDaoImpl")  
private UserDao userDao;  // 按名称注入

🔍 @Resource vs @Autowired 对比

特性@Resource@Autowired
来源Java标准注解Spring特有注解
包名jakarta.annotation.Resourceorg.springframework.beans.factory.annotation.Autowired
注入策略先按名称,再按类型先按类型,再按名称
支持@Qualifier❌ 不支持✅ 支持
支持required属性❌ 不支持✅ 支持
适用场景标准Java EE项目Spring项目

💡 使用建议:

  1. Spring项目推荐@Autowired(更灵活)
  2. Java EE标准@Resource(更好的移植性)
  3. 按名称注入@Resource(name="xxx")
  4. 按类型注入@Autowired@Resource

💡 最佳实践

  1. 遵循标准项目结构
    将你的启动类放在一个顶层的根包中,所有其他业务代码都放在这个根包的子包里。这是解决扫描问题的最佳“预防针”。

  2. 显式处理多实现
    当你知道一个接口会有多个实现时,不要等到报错。主动使用@Primary@Qualifier来明确依赖关系,让代码意图更清晰。

  3. 优先使用@Service, @Repository, @Controller
    虽然@Component也行,但使用更具体的注解能让代码分层更明确,并且可以利用到@Repository的异常转译等额外功能。

  4. 谨慎使用@ComponentScan
    只有当你确实需要包含非标准路径下的组件时,才显式使用@ComponentScan。在大多数Spring Boot项目中,你根本不需要写这个注解。

🎯 总结

  1. 扫描不到Bean (NoSuchBeanDefinitionException):首先检查①是否忘记注解,其次检查②是否在扫描路径下
  2. Bean不唯一 (NoUniqueBeanDefinitionException):使用**@Primary指定默认实现,或使用@Qualifier**精确注入。
  3. @SpringBootApplication:它的位置决定了默认的扫描根路径,至关重要。
    理解了Spring组件扫描的原理和这几个常见问题的模式后,你就能在遇到问题时从容应对,快速定位并解决问题。一个结构清晰、扫描路径明确的项目,是构建健壮、可维护应用的第一步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/921947.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/921947.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【 运维相关】-- HTTP 压测/负载发生器之新秀 oha

目录 oha 项目分析&#xff08;hatoo/oha&#xff09; 一、概述 二、安装 三、快速上手 三、常用参数&#xff08;摘选&#xff09; 四、输出解读&#xff08;终端 TUI&#xff09; 五、与其它工具对比 六、最佳实践 七、注意事项 八、参考 oha 项目分析&#xff08;h…

淘宝闪购基于FlinkPaimon的Lakehouse生产实践:从实时数仓到湖仓一体化的演进之路

摘要&#xff1a;本文整理自淘宝闪购(饿了么)大数据架构师王沛斌老师在 Flink Forward Asia 2025 城市巡回上海站的分享。引言在数字化转型的浪潮中&#xff0c;企业对实时数据处理的需求日益增长。传统的实时数仓架构在面对业务快速变化和数据规模爆炸性增长时&#xff0c;逐渐…

Android应用添加日历提醒功能

功能 在安卓应用里调用系统日历&#xff0c;直接创建一个带提醒的日历事件&#xff0c;甚至不需要跳转到日历界面&#xff0c;只需要获取系统日历的读取权限即可。 需要的权限 在AndroidManifest.xml里添加 <uses-permission android:name"android.permission.READ_CAL…

‌Git Bisect 二分查找定位错误总结

# Git Bisect 二分查找指南## 1. 基本原理&#xff08;ASCII示意图&#xff09; 假设提交历史是一条时间线&#xff0c;Ggood&#xff08;正常&#xff09;&#xff0c;Bbad&#xff08;异常&#xff09;&#xff1a;提交顺序: G --- G --- G --- B --- B --- B | | | 初始正常…

ThingsKit物联网平台 v2.0.0 发布|前端UI重构、底层架构升级

v2.0.0 Release发布日期&#xff1a;2025/08/25 代码标签&#xff1a;v2.0.0_Release&#x1f947; 新增功能国标级联&#xff08;支持上级、下级国标级联&#xff09;视频回放、录像计划&#xff08;用户可以通过录像计划生成对应的视频回放并查看&#xff09;Modbus_TCP协…

Lua > Mac Mini M4安装openresty

Mac Mini M4安装openresty 主要参考 https://www.cnblogs.com/helios-fz/p/15703260.html brew uninstall nginxbrew update brew install pcre openssl #brew install geoip# brew tap openresty/brew # brew install openresty # brew install openresty/brew/openresty# VER…

【多线程案例】:单例模式

多线程案例8.1 单例模式饿汉模式懒汉模式懒汉模式-单线程版懒汉模式-多线程版懒汉模式-多线程版(改进)8.1 单例模式 单个实例. 在一个 java 进程中, 要求指定的类,只能有唯–个实例。&#xff08;尝试 new 多个实例的时候, 就会直接编译报错&#xff09; 单例模式是校招中最常…

【Python/Pytorch】-- 贝叶斯定理

文章目录 文章目录01 贝叶斯定理的理解02 在MRI重建领域应用01 贝叶斯定理的理解 贝叶斯定理的基本公式&#xff1a;P(A|B)P(B|A)*P(A) / P(B) 首先是如何理解这个公式&#xff1f; 在B事件发生的条件下&#xff0c;A发生的概率 P(A|B) 在B事件发生的条件下&#xff0c;A和B同…

子网掩码的隐形陷阱:为何能ping通却无法HTTPS访问

问题现象深度解析在近期企业网络维护中&#xff0c;运维团队发现一个具有教学意义的典型案例&#xff1a;某台部署在10.165.111.0/24网段的业务服务器&#xff08;10.165.111.71&#xff09;可以成功ping通目标中间件主机(10.165.110.11)&#xff0c;但通过HTTPS协议访问https:…

【ArcGIS】如何编辑图层的属性表

GIS按属性选择后删除所选项呈现灰色_arcgis删除字段灰色-CSDN博客

大数据各组件flume,datax,presto,DolphinScheduler,findBI在大数据数仓架构中的作用和功能。

一、数据仓库核心价值铺垫在讲具体技术前&#xff0c;先明确数据仓库&#xff08;Data Warehouse&#xff0c;简称数仓&#xff09; 的核心作用&#xff1a; 数据仓库是 “整合企业多源数据、按业务主题组织、支持决策分析” 的结构化数据存储体系&#xff0c;核心价值是打破数…

React From表单使用Formik和yup进行校验

一、Formik的使用 官方文档地址&#xff1a;https://formik.org/docs/tutorial#validation 首先安装依赖 yarn add formik2.导入并初始化 import { useFormik } from formik; initialValues&#xff1a;初始化 输入框的密码和账号 onSubmit&#xff1a;当点击提交按钮时&am…

netty-scoket.io路径配置

1、服务端代码 package com.yh.service.socket;import com.corundumstudio.socketio.SocketIOServer; import com.corundumstudio.socketio.store.RedissonStoreFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory…

20250910荣品RD-RK3588-MID开发板在Android13系统下解决点卡迪的屏闪屏的问题

20250910荣品RD-RK3588-MID开发板在Android13系统下解决点卡迪的屏闪屏的问题 2025/9/5 15:44缘起&#xff1a;荣品RD-RK3588-MID开发板在Android13系统下解决点卡迪的屏。 按 POWER按键 关机之后&#xff0c;2s之内再次短按 POWER按键&#xff0c;开机之后屏会抖动。 2s后短按…

正态分布 - 计算 Z-Score 的 无偏估计

正态分布 - 计算 Z-Score 的 无偏估计 flyfish Z-Score公式与计算步骤 1 公式&#xff08;样本Z-Score&#xff09; 实际应用中&#xff0c;我们几乎不知道“总体均值/标准差”&#xff0c;所以常用样本数据计算&#xff1a; zixi−xˉsz_i \frac{x_i - \bar{x}}{s}zi​sxi​−…

ai生成文章,流式传输(uniapp,微信小程序)

1.环境nutui-uniappvue3tsunocss2.功能源码包含ai生成逻辑&#xff0c;内容生成实时打字机功能&#xff0c;ai数据处理等<script setup lang"ts"> import {queryAIParams, } from /api/pagesA import { submitFn } from /api/aiimport Navbar from /component…

Linux设备内存不足如何处理

[rootlocalhost ~]# free -mtotal used free shared buff/cache available Mem: 31208 14317 1280 1551 15610 14657 Swap: 15927 2781 13146 [rootlocalhost ~]#从 free -m 输出来看&…

中间件八股

文章目录RedisRedis为什么快&#xff1f;Redis Redis为什么快&#xff1f; 首先它是内存数据库&#xff0c;所有数据直接操作内存而非磁盘&#xff0c;避免了 I/O 瓶颈&#xff1b;其次采用单线程模型&#xff0c;消除了多线程切换的开销&#xff0c;同时通过非阻塞 I/O 多路…

【参数详解与使用指南】PyTorch MNIST数据集加载

# 加载MNIST数据集 train_dataset datasets.MNIST(root./data, trainTrue, downloadTrue, transformtransform) # 下载训练集 test_dataset datasets.MNIST(root./data, trainFalse, downloadTrue, transformtransform) # 下载测试集在深度学习入门过程中&#xff0c;MNIST手…

闭包面试题

闭包&#xff08;Closure&#xff09; 是指一个函数能够记住并访问其词法作用域&#xff08;定义时的作用域&#xff09;&#xff0c;即使该函数在其词法作用域之外执行。一、通俗理解&#xff08;面试可这样开头&#xff09;&#xff1a;> 闭包就是一个函数“记住”了它出生…