文章目錄
- 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 容器的資源不由資源雙方管理,而由不使用資源的第三方管理,這可以帶來很多好處:
- 資源集中管理: loC 容器會幫我們管理一些資源 (對象等),我們需要使用時,只需要從 loC 容器中去取就可以了,實現資源的可配置和易管理
- 我們在創建實例時不需要了解其中的細節,降低了資源雙方的依賴程度,也就是耦合度
總結
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 中取出對象并注入到需要使用的類中就行了
- 組件注冊(交給 Spring 管理 —— 存):使用
@Component
及其派生注解(如@Controller
、@Service
、@Repository
、@Configuration
)可以將類標記為 Spring 管理的 Bean。這些注解會觸發組件掃描機制,使 Spring 自動發現并注冊這些類 - 依賴注入(取):使用
@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
類注解是添加到某個類上的,但是存在兩個問題:
- 使用外部包里的類,沒辦法添加類注解
- 五大注解交給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 給我們提供了三種方式:
- 屬性注入 (Field Injection)
- 構造方法注入 (Constructor Injection)
- 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();}
}
三種注入優缺點分析
- 屬性注入
- 優點:代碼簡潔直觀,通過
@Autowired
直接標記字段即可注入,開發效率高 - 缺點:強依賴 IoC 容器。無法注入 final 修飾的字段(因為字段初始化依賴容器注入,而 final 要求構造時賦值)
- 構造函數注入
-
優點:支持注入 final 修飾的字段(構造方法執行時初始化,符合 final 語義)。
依賴在類創建階段(構造方法執行)就完成注入,保證對象使用時依賴已完全初始化。
通用性強:構造方法是 JDK 基礎特性,不依賴框架,切換框架時無需修改注入邏輯。
注入的對象狀態穩定(依賴不可變),避免后續被意外修改。 -
缺點:若類依賴多個對象,構造方法參數會增多,代碼略顯繁瑣。
- 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提供了以下幾種解決方案:
- @Primary
- @Qualifier
- 改成 Bean的名稱
- @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;
}