Spring IoC DI介紹

文章目錄

  • IoC & DI 介紹
    • IoC介紹
    • DI 介紹
  • 組件注冊
    • Bean 命名約定
    • 方法注解 @Bean
    • 總結
  • 掃描路徑
  • DI 詳解
    • 屬性注入
    • 構造方法注入
    • Setter 注入
    • 三種注入優缺點分析
  • 當同一類型存在多個Bean時,直接使用@Autowired會存在問題
    • 使用@Primary注解
    • 使用@Qualifier注解
    • 使用Bean的名稱
    • 使用@Resource注解

IoC & DI 介紹

IoC介紹

Spring 是什么?

Spring 是一個開源框架,讓我們的開發更加簡單。我們用一句更具體的話來概括 Spring,那就是:Spring 是包含了眾多工具方法的 IoC 容器

那么問題來了,什么是容器?什么是 IoC 容器?接下來我們一起來看

什么是容器?

容器是用來容納某些物品的裝置。生活中的水壺,冰箱都是容器。Java中 List,Map 等集合類(數據存儲容器),Tomcat(Web 容器) 也是容器

什么是 IoC: Inversion of Control (控制反轉)?

IoC 是 Spring 的核心思想。其實在類上面添加 @RestController 或者@Controller 注解,就是把這個對象交給 Spring 管理,Spring 框架啟動時就會加載該類。而把對象交給 Spring 管理這個理念,就是 IoC 思想

什么是控制反轉呢?

也就是控制權反轉(獲得依賴對象的過程被反轉了)

當需要某個對象時,傳統開發模式中需要自己 new 對象,而 IoC 不需要自己創建,是把創建對象的任務交給容器,程序中只需要依賴注入 (Dependency Injection,DI) 就可以了,這個容器稱為 IoC 容器, Spring 就是一個 IoC 容器,所以有時 Spring 也稱為 Spring 容器

示例:造一輛車(分為四部分:輪子,底盤,車身,汽車)

傳統程序開發的實現思路是這樣的:先設計輪子(Tire),然后根據輪子的大小設計底盤(Bottom),接著根據底盤設計車身(Framework),最后根據車身設計好整個汽車(Car)。這里就出現了一個"依賴"關系:汽車依賴車身,車身依賴底盤,底盤依賴輪子

實現代碼如下:

public class NewCarExample {public static void main(String[] args) {Car car = new Car();car.run();}//汽車static class Car {private Framework framework;public Car() {framework = new Framework();System.out.println("Car init....");}public void run() {System.out.println("Car run...");}}//車身static class Framework {private Bottom bottom;public Framework() {bottom = new Bottom();System.out.println("Framework init...");}}//底盤static class Bottom {private Tire tire;public Bottom() {this.tire = new Tire();System.out.println("Bottom init...");}}//輪胎static class Tire {// 尺寸private int size;public Tire() {this.size = 17;System.out.println("輪胎尺寸: " + size);}}
}

這樣設計看起來沒問題,但是可維護性很低

比如接下來需求有了變更:我們需要加工多種尺寸的輪胎。那這個時候就要對上面的程序進行修改了,修改后的代碼如下所示:

public class NewCarExample {public static void main(String[] args) {Car car = new Car(20);car.run();}//汽車static class Car {private Framework framework;public Car(int size) {framework = new Framework(size);System.out.println("Car init...");}public void run() {System.out.println("Car run...");}}//車身static class Framework {private Bottom bottom;public Framework(int size) {bottom = new Bottom(size);System.out.println("Framework init...");}}//底盤static class Bottom {private Tire tire;public Bottom(int size) {this.tire = new Tire(size);System.out.println("Bottom init...");}}//輪胎static class Tire {// 尺寸private int size;public Tire(int size) {this.size = size;System.out.println("輪胎尺寸:" + size);}}
}

在上面的程序中,我們是根據輪子的尺寸設計的底盤,輪子的尺寸一改,底盤的設計就得修改。同樣因為我們是根據底盤設計的車身,那么車身也得改,同理汽車設計也得改,也就是整個設計幾乎都得改

問題就是:當最底層類創建或減少參數之后,整個調用鏈上的所有類都需要修改。程序的耦合度非常高 (修改一處代碼,影響其他處的代碼修改)

此時,我們可以把上級類自己創建下級類的方式,改為傳遞的方式(也就是注入的方式),這樣即使下級類發生變化(創建或減少參數),當前類也無需修改任何代碼

基于以上思路,我們把示例改造一下,把創建子類的方式,改為注入傳遞的方式,具體實現代碼如下:

public class IocCarExample {public static void main(String[] args) {Tire tire = new Tire(20);Bottom bottom = new Bottom(tire);Framework framework = new Framework(bottom);Car car = new Car(framework);car.run();}static class Car {private Framework framework;public Car(Framework framework) {this.framework = framework;System.out.println("Car init...");}public void run() {System.out.println("Car run...");}}static class Framework {private Bottom bottom;public Framework(Bottom bottom) {this.bottom = bottom;System.out.println("Framework init...");}}static class Bottom {private Tire tire;public Bottom(Tire tire) {this.tire = tire;System.out.println("Bottom init...");}}static class Tire {private int size;public Tire(int size) {this.size = size;System.out.println("Tire init, size: " + size);}}
}

代碼經過以上調整,無論底層類如何變化,整個調用鏈都不用做任何改變,這樣就完成了代碼之間的解耦,從而實現了更加靈活、通用的程序設計了

IoC 優勢

傳統代碼中對象創建順序是:Car->Framework->Bottom->Tire
改進后的代碼的對象創建順序是:Tire->Bottom->Framework->Car

傳統代碼是 Car 控制并創建了 Framework,Framework 控制并創建了 Bottom,依次往下,而改進之后的控制權發生反轉,不再是使用方創建并控制依賴對象了,而是把依賴對象注入到當前對象中,依賴對象的控制權不再由當前類控制了,這樣的話,即使依賴類發生改變,當前類都是不受影響的,這就是典型的控制反轉,也就是 IoC 的實現思想

從上面可以看出,loC 容器的資源不由資源雙方管理,而由不使用資源的第三方管理,這可以帶來很多好處:

  1. 資源集中管理: loC 容器會幫我們管理一些資源 (對象等),我們需要使用時,只需要從 loC 容器中去取就可以了,實現資源的可配置和易管理
  2. 我們在創建實例時不需要了解其中的細節,降低了資源雙方的依賴程度,也就是耦合度

總結

IoC (控制反轉),就是將對象的控制權交給 Spring 的 IoC 容器,由 IoC 容器創建及管理對象

DI 介紹

上面學習了 loC, 那么什么是 DI: Dependency Injection (依賴注入)呢?

容器在運行期間,程序需要某個資源,此時容器就為其提供這個資源。動態的為應用程序提供運行時所依賴的資源,稱之為依賴注入

從這點來看,依賴注入(DI)和控制反轉(IoC)其實是從不同的角度描述同一件事情,就是指通過引入 IoC 容器,利用依賴關系注入的方式,實現對象之間的解耦

上述代碼中,是通過構造函數的方式,把依賴對象注入到需要使用的對象中的:輪胎注入到底盤,底盤再注入到車身,最后車身注入到汽車中

IoC 是一種思想,也是 “目標”,而思想只是一種指導原則,最終還是要有可行的落地方案,而 DI 就屬于具體的實現。所以也可以說,DI 是 IoC 的一種實現

對 IoC 和 DI 有了初步的了解,接下來我們具體學習 Spring IoC 和 DI 的代碼實現。既然 Spring 是一個 IoC(控制反轉)容器,作為容器,那么它就具備兩個最基礎的功能:存和取

Spring 容器管理的主要是對象,這些對象,我們稱之為 “Bean”。 我們把這些對象交由 Spring 管理,由 Spring 負責對象的創建和銷毀。我們程序只需要告訴 Spring 哪些需要存,以及如何從 Spring 中取出對象并注入到需要使用的類中就行了

  1. 組件注冊(交給 Spring 管理 —— 存):使用@Component及其派生注解(如@Controller@Service@Repository@Configuration)可以將類標記為 Spring 管理的 Bean。這些注解會觸發組件掃描機制,使 Spring 自動發現并注冊這些類
  2. 依賴注入(取):使用@Autowired注解可以自動注入依賴的 Bean。該注解可用于構造函數、Setter 方法或字段,讓 Spring 自動解析并注入所需的依賴對象

組件注冊

要把某個對象交給 IoC 容器管理,共有兩類注解可以實現:

  • 類注解: @Controller@Service@Repository@Component@Configuration
  • 方法注解: @Bean

接下來我們分別來看

使用 @Controller 存儲 Bean 的代碼如下所示:

//把 TestController 交給 Spring 管理,由 Spring 來管理對象
@org.springframework.stereotype.Controller
public class TestController {public void sayHi() {System.out.println("Hi");}
}

如何觀察這個對象已經存在 Spring 容器中了呢?

接下來我們學習如何從 Spring 容器中獲取對象

更改啟動類代碼如下,注意把類名換成自己的

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;@SpringBootApplication
public class J20250624Application {public static void main(String[] args) {//獲取Spring上下文對象,可以理解成拿到Spring容器ApplicationContext context = SpringApplication.run(J20250624Application.class, args);//從Spring上下文中獲取對象TestController bean = context.getBean(TestController.class);//使用對象System.out.println(bean);bean.sayHi();}
}

ApplicationContext 翻譯就是: Spring 上下文

因為對象都交給 Spring 管理了,所以對象要從 Spring 中獲取,那么就得先拿到 Spring 的上下文

關于上下文的概念

上下文就是指當前的運行環境。比如進行線程切換的時候,切換前會把線程的狀態信息暫時儲存起來,這里的上下文就包括了當前線程的信息,等下次該線程又得到 CPU 的時候,從上下文中拿到線程上次運行的信息

運行啟動類,觀察運行結果,發現成功從 Spring 中獲取到 TestController 對象,并執行 TestController 的 sayHi 方法

在這里插入圖片描述

如果把@Controller注釋掉,就會報錯

在這里插入圖片描述

在這里插入圖片描述

也就是沒有org.example.j20250624.TestController這個對象

那么自動創建的 Bean 的名稱是什么呢?

Bean 是 Spring 框架在運行時管理的對象,Spring 會給管理的對象起一個名字方便管理,根據 Bean 的名稱就可以獲取到對應的對象

Bean 命名約定

我們看下官方文檔的說明: Bean Overview :: Spring Framework

在這里插入圖片描述
程序開發人員不需要為 Bean 指定名稱, 如果沒有顯式的提供名稱,Spring容器自動為該 Bean 生成唯一的名稱

命名約定使用Java標準約定作為實例字段名。也就是說,Bean 名稱以小寫字母開頭,然后使用駝峰式大小寫

比如:

  • 類名:UserController,Bean的名稱為:userController
  • 類名:AccountManager,Bean的名稱為:accountManager
  • 類名:AccountService,Bean的名稱為:accountService

也有一些特殊情況,當類名有多個字符并且第一個和第二個字符都是大寫時,將保留原始的大小寫。規則與 java.beans.Introspector.decapitalize 定義的規則相同

比如:

  • 類名:UController,Bean的名稱為:UController
  • 類名:AManager,Bean的名稱為:AManager
public class Test {public static void main(String[] args) {String className = "UserController";System.out.println(Introspector.decapitalize(className));}
}

在這里插入圖片描述

public class Test {public static void main(String[] args) {String className = "UController";System.out.println(Introspector.decapitalize(className));}
}

在這里插入圖片描述

根據這個命名規則,我們來獲取 Bean

@SpringBootApplication
public class J20250624Application {public static void main(String[] args) {//獲取Spring上下文對象,可以理解成拿到Spring容器ApplicationContext context = SpringApplication.run(J20250624Application.class, args);// 從 Spring 上下文中獲取對象// 方式1:根據 bean 類型獲取TestController testController1 = context.getBean(TestController.class);// 方式2:根據 bean 名稱獲取(需強制類型轉換)TestController testController2 = (TestController) context.getBean("testController");// 方式3:根據 bean 名稱和類型獲取TestController testController3 = context.getBean("testController", TestController.class);// 驗證獲取的對象實例System.out.println(testController1);System.out.println(testController2);System.out.println(testController3);}
}

在這里插入圖片描述

地址一樣,說明對象是同一個。能獲取 Bean 對象,其實是 BeanFactory 提供的功能

ApplicationContext vs BeanFactory(常見面試題)

  • 從繼承關系和功能方面來說:Spring 容器有兩個頂級接口: BeanFactory 和 ApplicationContext。其中 BeanFactory 提供了基礎的訪問容器能力,而 ApplicationContext 屬于 BeanFactory 的子接口,它繼承了 BeanFactory 的所有功能之外,還添加了國際化、事件發布、AOP 等方面的支持
  • 從性能方面來說:ApplicationContext 是一次性加載并初始化所有的 Bean 對象,而 BeanFactory 是需要哪個才去加載哪個,因此 BeanFactory 更加輕量。兩者本質是時間與空間的權衡

除了@Controller,使用 @Service@Repository@Configuration@Component一樣也可以把類交給spring管理

為什么要這么多類注解?

這個也是和應用分層相呼應的。讓程序猿看到類注解之后,就能直接了解當前類的用途

  • @Controller:控制層。接收請求,對請求進行處理,并進行響應
  • @Service:業務邏輯層。處理具體的業務邏輯
  • @Repository:數據訪問層,也稱為持久層。負責數據訪問操作
  • @Configuration:配置層。處理項目中的一些配置信息
  • @Component:通用組件層。當一個類不好明確歸類到其他層的時候就可以用 @Component

程序的應用分層,調用流程如下:

在這里插入圖片描述

類注解之間的關系

查看 @Controller / @Service / @Repository / @Configuration 的源碼發現這些注解里面都有 @Component

@Component 是一個元注解,也就是說可以注解其他類注解,用于標識一個類為 Spring 管理的 Bean。當 Spring 進行組件掃描時,會自動發現并注冊被 @Component 標記的類。如 @Controller@Service@Repository 等。這些注解被稱為 @Component 的衍生注解

方法注解 @Bean

類注解是添加到某個類上的,但是存在兩個問題:

  1. 使用外部包里的類,沒辦法添加類注解
  2. 五大注解交給Spring管理的都是單例的。一個類,可能需要多個對象,比如多個數據源

這些場景,我們就需要使用方法注解 @Bean

我們先來看看方法注解如何使用:

public class User {private String name;private int age;public User(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}
public class BeanConfig {@Beanpublic User user(){return new User("zhangsan", 23);}
}

然而,當我們寫完以上代碼,嘗試獲取 Bean 對象中的 User 卻發現,根本獲取不到:

@SpringBootApplication
public class J20250624Application {public static void main(String[] args) {//獲取Spring上下文對象,可以理解成拿到Spring容器ApplicationContext context = SpringApplication.run(J20250624Application.class, args);// 從 Spring 上下文中獲取對象User user = context.getBean(User.class);//使用對象System.out.println(user);}
}

在這里插入圖片描述

這是因為@Bean必須搭配五大注解使用

@Component
public class BeanConfig {@Beanpublic User user(){return new User("zhangsan", 23);}
}

再次執行,運行結果如下:

在這里插入圖片描述

定義多個對象

比如多數據源的場景,類是同一個,但是配置不同,指向不同的數據源

如果讓Spring再管理一個User對象,用類型取會報錯

@Component
public class BeanConfig {@Beanpublic User user1(){return new User("zhangsan", 18);}@Beanpublic User user2(){return new User("lisi", 19);}
}
@SpringBootApplication
public class J20250624Application {public static void main(String[] args) {//獲取Spring上下文對象,可以理解成拿到Spring容器ApplicationContext context = SpringApplication.run(J20250624Application.class, args);// 從 Spring 上下文中獲取對象User user = context.getBean(User.class);//使用對象System.out.println(user);}
}

在這里插入圖片描述

報錯信息顯示:期望只有一個匹配,結果發現了兩個,user1,user2。@Bean管理的對象的名稱就是方法名

接下來我們根據名稱來獲取 bean 對象

@SpringBootApplication
public class J20250624Application {public static void main(String[] args) {//獲取Spring上下文對象,可以理解成拿到Spring容器ApplicationContext context = SpringApplication.run(J20250624Application.class, args);//根據bean名稱,從Spring上下文中獲取對象User user1 = (User) context.getBean("user1");User user2 = (User) context.getBean("user2");//使用對象System.out.println(user1);System.out.println(user2);}
}

運行結果:

在這里插入圖片描述

可以看到,@Bean 可以針對同一個類,定義多個對象

重命名 Bean

可以通過設置 name 屬性給 Bean 對象進行重命名,如下代碼所示:

@Component
public class BeanConfig {@Bean(name = {"u1","user1"})public User user1(){return new User("zhangsan", 18);}@Beanpublic User user2(){return new User("lisi", 19);}
}

此時我們使用 u1 也可以獲取到 User 對象了,如下代碼所示:

@SpringBootApplication
public class J20250624Application {public static void main(String[] args) {//獲取Spring上下文對象,可以理解成拿到Spring容器ApplicationContext context = SpringApplication.run(J20250624Application.class, args);//根據bean名稱,從Spring上下文中獲取對象User u1 = (User) context.getBean("u1");User user1 = (User) context.getBean("user1");User user2 = (User) context.getBean("user2");//使用對象System.out.println(u1);System.out.println(user1);System.out.println(user2);}
}

在這里插入圖片描述

name= 可以省略,如下代碼所示:

@Component
public class BeanConfig {@Bean({"u1","user1"})public User user1(){return new User("zhangsan", 18);}@Beanpublic User user2(){return new User("lisi", 19);}
}

只有一個名稱時, {}也可以省略, 如:

@Component
public class BeanConfig {@Bean("u1")public User user1(){return new User("zhangsan", 18);}@Beanpublic User user2(){return new User("lisi", 19);}
}

這樣原來的user1對象就沒有了

在這里插入圖片描述

總結

Bean 的命名

  • 五大注解存儲的 Bean

① 前兩位字母均為大寫,Bean 名稱為類名
② 其他的為類名首字母小寫
③ 重命名通過 value 屬性設置 @Controller (value = "user")

  • @Bean 注解存儲的 Bean

① Bean 名稱為方法名
② 重命名通過 name 屬性設置 @Bean (name = {"u1","user1"})


如果存在多個Bean, 根據類型去拿就會有問題,通過名稱不會有問題(名稱不會重復)

掃描路徑

Q: 五大注解和@Bean聲明的 bean,一定會生效嗎?
A: 不一定(原因: bean 想要生效,還需要被 Spring 掃描)

下面我們通過修改項目工程的目錄結構,來測試 Bean 對象是否生效:

記得把代碼改回正確的再測試

原本的目錄結構:

在這里插入圖片描述

因為現在啟動類測試的是@Bean創建的bean,把啟動類移動到configuration包下還是能正確運行的,所以就把啟動類放到controller包下進行測試

在這里插入圖片描述

@SpringBootApplication 內部已默認包含 @ComponentScan(默認掃描當前主啟動類所在包及其子包的組件),可以顯式添加 @ComponentScan 重新配置掃描路徑, 但默認的掃描邏輯會被覆蓋

@ComponentScan("org.example.j20250624.configuration")
@SpringBootApplication
public class J20250624Application {public static void main(String[] args) {//獲取Spring上下文對象,可以理解成拿到Spring容器ApplicationContext context = SpringApplication.run(J20250624Application.class, args);//根據bean名稱,從Spring上下文中獲取對象User u1 = (User) context.getBean("u1");User user1 = (User) context.getBean("user1");User user2 = (User) context.getBean("user2");//使用對象System.out.println(u1);System.out.println(user1);System.out.println(user2);}
}

這樣就能掃描到configuration包了

在這里插入圖片描述
加上{} 可以配置多個包路徑

@ComponentScan({"org.example.j20250624.configuration", "org.example.j20250624.model"})

DI 詳解

依賴注入是一個過程,是指 IoC 容器在創建 Bean 時,去提供運行時所依賴的資源,而資源指的就是對象。簡單來說,就是把對象取出來放到某個類的屬性中。

在一些文章中,依賴注入也被稱為 “對象注入”,“屬性裝配”,具體含義需要結合文章的上下文來理解

依賴注入是使用 @Autowired 實現的,Spring 給我們提供了三種方式:

  1. 屬性注入 (Field Injection)
  2. 構造方法注入 (Constructor Injection)
  3. Setter 注入 (Setter Injection)

下面我們按照實際開發中的模式,將 Service 類注入到 Controller 類中

屬性注入

Service 類的實現代碼如下:

@Service
public class UserService {public void sayHi() {System.out.println("Hi,UserService");}
}

Controller 類的實現代碼如下:

//注入方法1: 屬性注入@Controller
public class UserController {@Autowiredprivate UserService userService;public void sayHi(){System.out.println("hi,UserController...");userService.sayHi();}
}

調用 UserController 中的 sayHi 方法:

@SpringBootApplication
public class J20250624Application {public static void main(String[] args) {//獲取Spring上下文對象,可以理解成拿到Spring容器ApplicationContext context = SpringApplication.run(J20250624Application.class, args);//從Spring上下文中獲取對象UserController userController = (UserController) context.getBean("userController");//使用對象userController.sayHi();}
}

在這里插入圖片描述
去掉@Autowired , 再運行一下程序看看結果

在這里插入圖片描述

構造方法注入

構造方法注入是在類的構造方法中實現注入,如下代碼所示:

//注入方法2: 構造方法@Controller
public class UserController {private UserService userService;@Autowiredpublic UserController(UserService userService) {this.userService = userService;}public void sayHi(){System.out.println("hi,UserController2...");userService.sayHi();}
}

注意事項:如果類只有一個構造方法,那么 @Autowired 可以省略,Spring 會自動使用該構造方法進行依賴注入;如果類中有多個構造方法,那么需要加上 @Autowired 來明確指定使用哪個構造方法

@Controller
public class UserController {private UserService userService;private String name;// 構造方法1:注入 UserService@Autowired //必須指定public UserController(UserService userService) {this.userService = userService;}// 構造方法2:注入 UserService 和 namepublic UserController(UserService userService, String name) {this.userService = userService;this.name = name;}public void sayHi(){System.out.println("hi,UserController2...");userService.sayHi();}
}

Setter 注入

Setter 注入和屬性的 Setter 方法實現類似,只不過在設置 Setter 方法的時候加上 @Autowired ,如下代碼所示:

//注入方法3: Setter方法注入@Controller
public class UserController {private UserService userService;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}public void sayHi(){System.out.println("hi,UserController3...");userService.sayHi();}
}

三種注入優缺點分析

  1. 屬性注入
  • 優點:代碼簡潔直觀,通過 @Autowired 直接標記字段即可注入,開發效率高
  • 缺點:強依賴 IoC 容器。無法注入 final 修飾的字段(因為字段初始化依賴容器注入,而 final 要求構造時賦值)
  1. 構造函數注入
  • 優點:支持注入 final 修飾的字段(構造方法執行時初始化,符合 final 語義)。
    依賴在類創建階段(構造方法執行)就完成注入,保證對象使用時依賴已完全初始化。
    通用性強:構造方法是 JDK 基礎特性,不依賴框架,切換框架時無需修改注入邏輯。
    注入的對象狀態穩定(依賴不可變),避免后續被意外修改。

  • 缺點:若類依賴多個對象,構造方法參數會增多,代碼略顯繁瑣。

  1. Setter 注入
  • 優點:支持對象創建后動態修改依賴,靈活度高,適合處理 “可選依賴”(依賴可后續配置,不影響類初始化)
  • 缺點:無法注入 final 修飾的字段(依賴通過 Setter 方法賦值,晚于 final 字段初始化時機)。
    依賴可能被多次修改(Setter 方法可被外部調用),存在狀態變更風險。

當同一類型存在多個Bean時,直接使用@Autowired會存在問題

@Component
public class BeanConfig {@Bean("u1")public User user1(){return new User("zhangsan", 18);}@Beanpublic User user2(){return new User("lisi", 19);}
}
@Controller
public class UserController {//注入user@Autowiredprivate User user;
}

在這里插入圖片描述

只需要一個Bean,但找到兩個

如何解決上述問題呢?Spring提供了以下幾種解決方案:

  1. @Primary
  2. @Qualifier
  3. 改成 Bean的名稱
  4. @Resource

使用@Primary注解

@Primary 注解的作用是在存在多個相同類型的 Bean 時,指定某個 Bean 作為默認注入選擇

@Component
public class BeanConfig {@Primary@Bean("u1")public User user1(){return new User("zhangsan", 18);}@Beanpublic User user2(){return new User("lisi", 19);}
}
@Controller
public class UserController {//注入user@Autowiredprivate User user;
}

使用@Qualifier注解

@Qualifier的value屬性中,指定當前要注入的Bean的名稱。@Qualifier注解不能單獨使用,必須配合@Autowired使用

@Component
public class BeanConfig {@Bean("u1")public User user1(){return new User("zhangsan", 18);}@Beanpublic User user2(){return new User("lisi", 19);}
}
@Controller
public class UserController {//注入user@Qualifier("u1")@Autowiredprivate User user;
}

使用Bean的名稱

@Component
class BeanConfig {@Beanpublic User user1(){return new User("zhangsan",18);}@Beanpublic User user2() {return new User("lisi",19);}
}
@Controller
public class UserController {@Autowiredprivate User user1;
}

使用@Resource注解

通過name屬性指定要注入的Bean的名稱

@Component
public class BeanConfig {@Bean("u1")public User user1(){return new User("zhangsan", 18);}@Beanpublic User user2(){return new User("lisi", 19);}
}
@Controller
public class UserController {//注入user@Resource(name = "u1")private User user;
}

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

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

相關文章

【Flutter】解決 flutter_inappwebview在 Windows 上使用導致應用閃退問題

問題背景 在 Windows 11 上運行 Flutter 桌面應用時,應用出現閃退現象。通過系統事件日志分析,發現是 MSVCP140.dll 模塊的訪問沖突異常(錯誤代碼 c0000005)導致的崩潰。 問題分析 1. 錯誤現象 應用啟動后立即閃退Windows 事件…

使用 JavaScript、Mastra 和 Elasticsearch 構建一個具備代理能力的 RAG 助手

作者:來自 Elastic JD Armada 了解如何在 JavaScript 生態系統中構建 AI 代理。 Elasticsearch 與業界領先的生成式 AI 工具和服務商有原生集成。查看我們的網絡研討會,了解如何超越 RAG 基礎,或使用 Elastic 向量數據庫構建可投入生產的應用…

Active Directory 環境下 Linux Samba 文件共享服務建設方案

Active Directory 環境下 Linux Samba 文件共享服務建設方案 目錄 需求分析方案總體設計技術架構與選型詳細部署規劃共享文件性能測試非域終端共享配置運維與權限安全管理建議1. 需求分析 因某公司(編的)新增多個部門,各部門之間存在多類型終端系統,但又有同時訪問文件庫…

Python爬蟲網安-項目-簡單網站爬取

源碼: https://github.com/Wist-fully/Attack/tree/pc pc_p1 目標: 1.進入列表頁,順著列表爬取每個電影詳情頁 2.利用正則來提取,海報,名稱,類別,上映的時間,評分,劇…

Golang中的數組

Golang Array和以往認知的數組有很大不同。有點像Python中的列表 1. 數組:是同一種數據類型的固定長度的序列。 2. 數組定義:var a [len]int,比如:var a [5]int,數組長度必須是常量,且是類型的組成部分。一…

《Origin畫百圖》之矩陣散點圖

矩陣散點圖的作用 一、直觀展示多變量間的兩兩關系 矩陣散點圖的基本單元是兩兩變量的散點圖,每個散點圖對應矩陣中的一個單元格,可直接反映變量間的: 相關性方向:正相關(散點向右上傾斜)或負相關&#x…

Flask文件下載send_file中文文件名處理解決方案

Flask文件下載send_file中文文件名處理解決方案 Flask文件下載中文文件名處理解決方案問題背景問題分析核心問題常見癥狀 解決方案技術實現關鍵技術點 完整實現示例 Flask文件下載中文文件名處理解決方案 問題背景 在Web應用開發中,當用戶下載包含中文字符的文件時…

新手指南:在 Ubuntu 上安裝 PostgreSQL 并通過 VS Code 連接及操作

本文檔記錄了一個初學者在 Ubuntu 系統上安裝、配置 PostgreSQL 數據庫,并使用 Visual Studio Code (VS Code) 作為客戶端進行連接和操作的全過程。其中包含了遇到的常見錯誤、分析和最終的解決方案,旨在為新手提供一個清晰、可復現的操作路徑。 最終目…

二刷 蒼穹外賣day10(含bug修改)

Spring Task Spring框架提供的任務調度工具,可以按照約定的時間自動執行某個代碼邏輯 cron表達式 一個字符串,通過cron表達式可以定義任務觸發的時間 **構成規則:**分為6或7個域,由空格分隔開,每個域代表一個含義 …

Android Native 之 inputflinger進程分析

Android IMS原理解析 - 簡書 Android 輸入事件分發全流程梳理(一)_android input事件分發流程-CSDN博客 Android 輸入事件分發全流程梳理(二)_android輸入事件流程圖-CSDN博客 inputflinger模塊與surfaceflinger模塊在同級目錄…

Python實例題:基于 Flask 的在線聊天系統

目錄 Python實例題 題目 要求: 解題思路: 代碼實現: Python實例題 題目 基于 Flask 的在線聊天系統 要求: 使用 Flask 框架構建一個實時在線聊天系統,支持以下功能: 用戶注冊、登錄和個人資料管理…

v-bind指令

好的,我們來學習 v-bind 指令。這個指令是理解 Vue 數據驅動思想的基石。 核心功能:v-bind 的作用是將一個或多個 HTML 元素的 attribute (屬性) 或一個組件的 prop (屬性) 動態地綁定到 Vue 實例的數據上。 簡單來說,它在你的數據和 HTML …

【設計模式04】單例模式

前言 整個系統中只會出現要給實例,比如Spring中的Bean基本都是單例的 UML類圖 無 代碼示例 package com.sw.learn.pattern.B_create.c_singleton;public class Main {public static void main(String[] args) {// double check locking 線程安全懶加載 ?? //…

飛算科技依托 JavaAI 核心技術,打造企業級智能開發全場景方案

在數字經濟蓬勃發展的當下,企業對智能化開發的需求愈發迫切。飛算數智科技(深圳)有限公司(簡稱 “飛算科技”)作為自主創新型數字科技公司與國家級高新技術企業,憑借深厚的技術積累與創新能力,以…

20250701【二叉樹公共祖先】|Leetcodehot100之236【pass】今天計劃

20250701 思路與錯誤記錄1.二叉樹的數據結構與初始化1.1數據結構1.2 初始化 2.解題 完整代碼今天做了什么 題目 思路與錯誤記錄 1.二叉樹的數據結構與初始化 1.1數據結構 1.2 初始化 根據列表,順序存儲構建二叉樹 def build_tree(nodes, index0):# idx是root開始…

Web應用開發 --- Tips

Web應用開發 --- Tips General后端需要做參數校驗代碼風格和Api設計風格的一致性大于正確性數據入庫時間應由后端記錄在對Api修改的時候,要注意兼容情況,避免breaking change 索引對于查詢字段,注意加索引對于唯一的字段,考慮加唯…

CSS 安裝使用教程

一、CSS 簡介 CSS(Cascading Style Sheets,層疊樣式表)是用于為 HTML 頁面添加樣式的語言。通過 CSS 可以控制網頁元素的顏色、布局、字體、動畫等,是前端開發的三大核心技術之一(HTML、CSS、JavaScript)。…

機器學習中為什么要用混合精度訓練

目錄 FP16與顯存占用關系機器學習中一般使用混合精度訓練:FP16計算 FP32存儲關鍵變量。 FP16與顯存占用關系 顯存(Video RAM,簡稱 VRAM)是顯卡(GPU)專用的內存。 FP32(單精度浮點)&…

[附源碼+數據庫+畢業論文+答辯PPT]基于Spring+MyBatis+MySQL+Maven+vue實現的中小型企業財務管理系統,推薦!

摘 要 現代經濟快節奏發展以及不斷完善升級的信息化技術,讓傳統數據信息的管理升級為軟件存儲,歸納,集中處理數據信息的管理方式。本中小型企業財務管理就是在這樣的大環境下誕生,其可以幫助管理者在短時間內處理完畢龐大的數據信…

華為云Flexus+DeepSeek征文 | 對接華為云ModelArts Studio大模型:AI賦能投資理財分析與決策

引言:AI金融,開啟智能投資新時代?? 隨著人工智能技術的飛速發展,金融投資行業正迎來前所未有的變革。??華為云ModelArts Studio??結合??Flexus高性能計算??與??DeepSeek大模型??,為投資者提供更精準、更高效的投資…