深入拆解Spring思想:DI(依賴注入)

  • 在簡單了解IoC與DI中我們已經了解了DI的基本操作,接下來我們來詳解DI。(IoC詳解請看這里)
  • 我們已經知道DI是“你給我,我不用自己創建”的原則。現在我們來看看Spring是如何實現“給”這個動作的,也就是依賴注入的幾種方式。

Spring主要提供了三種注入方式,都是通過 @Autowired 注解配合完成的:

  1. 屬性注入 (Field Injection):直接在字段上使用 @Autowired
  2. 構造方法注入 (Constructor Injection):在類的構造方法上使用 @Autowired
  3. Setter 注入 (Setter Injection):在Setter方法上使用 @Autowired

三種注入方式

屬性注入

方式:直接在需要注入的屬性(字段)上加上 @Autowired

代碼示例
首先,我們有一個 UserService Bean:

@Service // 告訴Spring:我是UserService,請你管理我
public class UserService {public void sayHi() {System.out.println("Hi, UserService");}
}

然后,在 UserController 中注入 UserService

@Controller
public class UserController {@Autowired // 告訴Spring:我需要一個UserService,請你直接注入到這個屬性里private UserService userService;public void sayHi() {System.out.println("Hi, UserController...");userService.sayHi(); // 使用注入的UserService}
}

獲取并使用

@SpringBootApplication
public class SpringTocDemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringTocDemoApplication.class, args);UserController userController = context.getBean(UserController.class);userController.sayHi();}
}

運行結果

Hi, UserController...
Hi, UserService

解釋:Spring成功地將 UserService 實例注入到了 UserControlleruserService 屬性中。

注意:如果你嘗試在沒有Spring容器的情況下直接調用 UserControllersayHi() 方法,userService 會是 null,導致空指針異常(NPE),因為Spring沒有機會注入它。

構造方法注入

方式:在類的構造方法上加上 @Autowired。Spring會在創建這個類實例時,通過調用這個構造方法來注入依賴。

代碼示例

@Controller
public class UserController2 {private UserService userService;@Autowired // 告訴Spring:請通過這個構造方法注入UserServicepublic UserController2(UserService userService) {this.userService = userService;}public void sayHi() {System.out.println("Hi, UserController2...");userService.sayHi();}
}

注意

  • 如果一個類只有一個構造方法,那么即使不加 @Autowired,Spring也會自動使用它進行注入(Spring 4.3+)。

[!TIP] 此時默認的無參構造方法不生效了,最好的習慣是補上默認的無參構造方法

  1. Spring默認的是使用無參的構造方法(如有多個構造方法)
  • 這樣會導致之后在使用到userService的地方有空指針報錯異常(可以通過打印日志的方法來確定具體使用哪一個方法)
  • 所以有多個構造方法的情況下,需要在需要的構造方法上加上 @Autowired注解表示指定使用哪一個

Setter 注入

方式:在Setter方法上加上 @Autowired。Spring會先創建對象,然后調用對應的Setter方法來注入依賴。

代碼示例

@Controller
public class UserController3 {private UserService userService;@Autowired // 告訴Spring:請通過這個Setter方法注入UserServicepublic void setUserService(UserService userService) {this.userService = userService;}public void sayHi() {System.out.println("Hi, UserController3...");userService.sayHi();}
}

[!QUESTION] 如果 setUserService 方法上沒有 @Autowired,Spring還能注入嗎?
不能。Spring需要 @Autowired 來知道這個方法是用來注入依賴的。

三種注入方式優缺點分析

#面經

方式優點缺點
屬性注入最簡潔,使用方便。1. 違反單一職責原則(SRP)。
2. 難以測試(只能用于IoC容器,并且在使用的時候才會出現空指針異常)。
3. 無法聲明為 final
構造方法注入1. 依賴明確,強制依賴。
2. 可以聲明為 final(推薦)。
3. 保證對象完全初始化。因為依賴是在類的構造方法中執行的,而構造方法是在類加載階段就會執行的方法.
4. 更好的可測試性。
5. 通用性好,因為構造方法是JDK支持的,所以換任何框架都是使用的。
1. 依賴過多時,構造方法參數列表會很長。
Setter 注入1. 依賴可選(不強制)。
2. 可以在對象創建后進行配置。
1. 無法聲明為 final
2. 可能會被多次調用,存在風險。

推薦:在大多數情況下,構造方法注入是最佳實踐。它確保了依賴的不可變性,并使對象在創建時就處于完全可用的狀態。

@Autowired 存在問題?

問題:如果Spring容器中有多個相同類型的Bean,@Autowired 會怎么做?

代碼示例
我們定義了兩個 User 類型的Bean,名字分別是 user1user2

@Configuration
public class BeanConfig {@Bean("user1")public User user1() { /* ... */ }@Bean("user2")public User user2() { /* ... */ }
}

現在,我們在 UserController 中嘗試注入 User

@Controller
public class UserController {@Autowiredprivate UserService userService; // 假設只有一個UserService@Autowiredprivate User user; // 嘗試注入Userpublic void sayHi() {System.out.println("Hi, UserController...");userService.sayHi();System.out.println(user); // 打印注入的User}
}

運行結果

// 報錯:NoUniqueBeanDefinitionException: No qualifying bean of type 'User' available: expected single matching bean but found 2

解釋:Spring發現有兩個 User 類型的Bean(user1user2),它不知道該注入哪一個,所以報錯了。

如何解決“多個相同類型Bean”的問題?

Spring提供了幾種方式來解決歧義:

  1. @Primary:優先注入。
  2. @Qualifier:指定Bean的名稱。
    • @Qualifier 優先級比 @Primary
  3. @Resource:按名稱注入(JDK標準)。
@Primary

作用:當有多個相同類型的Bean時,給其中一個加上 @Primary,表示它是首選的。

代碼示例

@Configuration
public class BeanConfig {@Bean("user1")@Primary // 告訴Spring:當需要User類型時,優先注入我public User user1() { /* ... */ }@Bean("user2")public User user2() { /* ... */ }
}

現在,UserController 再次注入 User

@Controller
public class UserController {@Autowiredprivate User user; // 會自動注入user1// ...
}

解釋:當Spring需要注入 User 類型時,它會優先選擇帶有 @Primaryuser1

@Qualifier

作用:明確指定要注入哪個Bean的名稱。

代碼示例

@Controller
public class UserController {@Autowired@Qualifier("user2") // 告訴Spring:我要注入名為“user2”的User Beanprivate User user;// ...
}

解釋@Qualifier 必須和 @Autowired 一起使用。它告訴Spring,即使有多個 User 類型的Bean,我只想要那個名字是 user2 的。

[!IMPORTANT] @Qualifier注解不能單獨使?,必須配合@Autowired使?

@Resource

作用@Resource 是JDK提供的注解,它默認是按名稱進行注入。如果找不到同名的Bean,再嘗試按類型注入。

代碼示例

@Controller
public class UserController {@Resource(name = "user1") // 告訴Spring:我要注入名為“user1”的Beanprivate User user;// ...
}

[[四種不同情況反應構造Spring框架中Bean的依賴注入和自動裝配的不同規則]]

#面經
@Autowired vs @Resource 的區別:

  1. @Autowired是spring提供的注解,@Resource是JDK提供的注解
  • @Autowired:Spring特有的,默認按類型注入。如果類型有多個,再嘗試按名稱匹配。
  • @Resource:JDK標準,默認按名稱注入。如果名稱找不到,再嘗試按類型匹配,并且其支持更多的參數設置,如name:根據名稱獲取Bean

Autowired裝配順序

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/88419.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/88419.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/88419.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Arcgis連接HGDB報錯

文章目錄環境癥狀問題原因解決方案環境 系統平臺:Linux x86-64 Red Hat Enterprise Linux 7 版本:6.0 癥狀 Arcgis連接HGDB報錯: 無法連接到數據庫服務器來檢索數據庫列表;請檢查服務器名稱、用戶名和密碼信息,然后…

Android 應用常見安全問題

背景:OWASP MASVS(Mobile Application Security Verification Standard 移動應用安全驗證標準)是移動應用安全的行業標準。 一、MASVS-STORAGE:存儲 1.1 不當暴露FileProvider目錄 配置不當的 FileProvider 會無意中將文件和目錄暴露給攻擊者…

Netty的內存池機制怎樣設計的?

大家好,我是鋒哥。今天分享關于【Netty的內存池機制怎樣設計的?】面試題。希望對大家有幫助; Netty的內存池機制怎樣設計的? 超硬核AI學習資料,現在永久免費了! Netty的內存池機制是為了提高高并發環境下的內存分配與回收效率…

Python 項目快速部署到 Linux 服務器基礎教程

Linux的開源特性和強大的命令行工具使得部署流程高度自動化,可重復性強。本文將詳細介紹如何從零開始快速部署Python項目到Linux服務器。 Linux系統因其穩定性、安全性和性能優化,成為Python項目部署的首選平臺。無論是使用flask構建Web應用、FastAPI創…

SQL Server通過CLR連接InfluxDB實現異構數據關聯查詢技術指南

一、背景與需求場景 在工業物聯網和金融監控場景中,實時時序數據(InfluxDB)需與業務元數據(SQL Server)聯合分析: 工業場景:設備傳感器每秒采集溫度、振動數據(InfluxDB),需關聯工單狀態、設備型號(SQL Server)金融場景:交易流水時序數據(每秒萬條)需實時匹配客…

機器學習詳解

## 深入解析機器學習:核心概念、方法與未來趨勢機器學習(Machine Learning, ML)作為人工智能的核心分支,正深刻重塑著我們的世界。本文將系統介紹機器學習的基本概念、主要方法、實際應用及未來挑戰,為您提供全面的技術…

汽車間接式網絡管理的概念

在汽車網絡管理中,直接式和間接式管理是兩種用于協調車載電子控制單元(ECUs)之間通信與行為的機制。它們主要用于實現車輛內部不同節點之間的協同工作,特別是在涉及網絡喚醒、休眠、狀態同步等場景中。### 直接式管理直接式網絡管…

npm : 無法加載文件 D:\Node\npm.ps1,因為在此系統上禁止運行腳本。

npm : 無法加載文件 D:\Node\npm.ps1,因為在此系統上禁止運行腳本。 安裝高版本的node.js,可能會導致這個問題, 腳本的權限被限制了,需要你設置用戶權限。 get-ExecutionPolicy set-ExecutionPolicy -Scope CurrentUser remotesig…

搜索算法講解

搜索算法講解 深度優先搜索-DFS P1219 [USACO1.5] 八皇后 Checker Challenge 一個如下的 666 \times 666 的跳棋棋盤,有六個棋子被放置在棋盤上,使得每行、每列有且只有一個,每條對角線(包括兩條主對角線的所有平行線&#xff…

深度學習---Rnn-文本分類

# 導入PyTorch核心庫 import torch # 導入神經網絡模塊 import torch.nn as nn # 導入優化器模塊 import torch.optim as optim # 導入函數式API模塊 import torch.nn.functional as F # 導入數據集和數據加載器 from torch.utils.data import Dataset, DataLoader # 導入NumPy…

20250709解決KickPi的K7開發板rk3576-android14.0-20250217.tar.gz編譯之后刷機啟動不了

【整體替換】 Z:\20250704\rk3576-android14.0\rkbin清理編譯的臨時結果: rootrootrootroot-X99-Turbo:~$ cd 14TB/versions/rk3576-android14.0-20250217k7/ rootrootrootroot-X99-Turbo:~/14TB/versions/rk3576-android14.0-20250217k7$ ll rootrootrootroot-X99-…

怎么創建新的vue項目

首先,新建一個文件點文件路徑,輸入cmd

CIU32L051系列 DMA串口無阻塞性收發的實現

1.CIU32L051 DMA的通道映射由于華大CIU32L051的DMA外設資源有限,DMA只有兩個通道可供使用,對應的通道映射圖如下:2.UART對應的引腳分布及其復用映射CIU32L051對應的UART對應的引腳映射圖如下,這里博主為了各位方便查找,就直接全拿…

飛算 JavaAI 體驗:重塑 Java 開發的智能新范式

飛算 JavaAI 體驗:重塑 Java 開發的智能新范式引言:正文:一、工程化代碼生成:從 "片段拼接" 到 "模塊交付"1.1 傳統工具的局限與突破1.2 代碼質量驗證二、智能重構引擎:從 "問題修復" 到…

深入理解JVM的垃圾收集(GC)機制

引言首先我們來介紹垃圾收集的概念,什么是垃圾收集?垃圾收集 (Garbage Collection,GC),顧名思義就是釋放垃圾占用的空間,防止內存爆掉。有效的使用可以使用的內存,對內存堆中已經死亡…

【筆記】國標-機動車輛及掛車分類

源于:GB/T 15089-2001機動車輛及掛車分類 1.L類:兩輪或三輪車輛2.M類:四輪載客車輛3.N類:四輪載貨車輛4.O類:掛車5.G類:其他

VLLM部署DeepSeek-LLM-7B-Chat 模型

一、部署環境準備1. 基礎環境要求操作系統:Linux(推薦歐拉系統、Ubuntu 等)Python 版本:3.8 及以上依賴工具:pip、git、curl可選依賴:GPU 環境:NVIDIA GPU(支持 CUDA 11.7&#xff0…

翱翔的智慧之翼:Deepoc具身智能如何賦能巡檢無人機“讀懂”工業現場

翱翔的智慧之翼:Deepoc具身智能如何賦能巡檢無人機“讀懂”工業現場在百米高的風力發電機葉片頂端,在蜿蜒數十公里的高壓輸電線旁,在油氣管道穿越的崇山峻嶺之上,一架四旋翼無人機正精準地懸停著,它的“眼睛”&#xf…

Java大廠面試實錄:謝飛機的電商場景技術問答(Spring Cloud、MyBatis、Redis、Kafka、AI等)

Java大廠面試實錄:謝飛機的電商場景技術問答(Spring Cloud、MyBatis、Redis、Kafka、AI等)本文模擬知名互聯網大廠Java后端崗位面試流程,以電商業務為主線,由嚴肅面試官與“水貨”程序員謝飛機展開有趣的對話&#xff…

Kotlin基礎

前言 Decrement(遞減) → 將一個值減 1 的操作 Predicate(謂詞) → 返回布爾值(邏輯值)的函數 Reference(引用) → 允許使用自定義名稱與對象交互 Runtime(運行時&…