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
英文地址,請注明出處:http://en.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;> 閉包就是一個函數“記住”了它出生…