一 自動注入@Autowire
代碼實現:
package org.example.spring01.service;import org.springframework.stereotype.Service;@Service
public class UserService {}
package org.example.spring01.controller;import lombok.Data;
import lombok.ToString;
import org.example.spring01.bean.Person;
import org.example.spring01.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;import java.util.List;
import java.util.Map;@ToString
@Data
@Controller
public class UserController {/*** 自動注入 原理:Spring調用容器的getBean方法* @Autowired* 只有且只找到一個,直接注入,名字無所謂* 如果找到多個在按照名稱去找,變量名就是名字*/@AutowiredUserService userService;@AutowiredList<Person> personList;@AutowiredMap<String,Person> personMap;}
package org.example.spring01;import org.example.spring01.controller.UserController;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplication
public class Spring01Application {public static void main(String[] args) {// 啟動springboot應用ConfigurableApplicationContext ioc = SpringApplication.run(Spring01Application.class, args);System.out.println("run = " + ioc);UserController bean = ioc.getBean(UserController.class);System.out.println("bean = " + bean);}
}
二 默認首選/指定Bean@Primary @Qualifier
1 概述:
-
@Primary
:“默認選我”,簡化多數場景的依賴注入。 -
@Qualifier
:“點名要誰”,精準控制依賴的選擇。
2 當某個 Bean 被標記為?
@Primary
,Spring 的依賴注入規則變為:
-
優先選擇?
@Primary
?的 Bean,無論字段名如何變化。 -
忽略屬性名匹配,直接注入?
@Primary
?標記的 Bean。
3 在沒有?
@Primary
?時,Spring 按以下順序解決依賴:
-
按類型匹配:尋找與字段類型一致的 Bean。
-
按名稱匹配:如果有多個同類型 Bean,嘗試將字段名與 Bean 的名稱(ID)匹配。
@Primary標記一個Bean,然后在注入時用@Autowired,這時候會自動選擇@Primary的;或者當有多個Bean時,用@Qualifier指定名稱來注入。
當同時存在?@Primary
?和?@Qualifier
?時,@Qualifier
?的優先級更高:
代碼實現:
// @Primary默認組件,不說明Person具體就是這個@Primary@Bean("LiSi")public Person lisi() {Person person = new Person();person.setAge(18);person.setGender("男");person.setName("李四");return person;}
代碼實現:
package org.example.spring01.service;import lombok.Data;
import org.example.spring01.bean.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;@Data // Lombok 注解,自動生成 getter/setter/toString 等方法
@Service // Spring 注解,標記為服務層 Bean
public class UserService {//如果容器中這種組件有多個,則使用@Qualifier注解精確指定注入的組件名@Qualifier("ZhangSan") // 指定注入名為 "ZhangSan" 的 Bean@Autowired // 自動注入依賴Person person; // 依賴的 Person 對象
}
三 自動注入@Resource
在選擇使用哪一個注解時,可以根據項目的具體需求和個人偏好來決定。在許多情況下,這兩種注解可以互換使用,特別是在只有一個符合條件的bean的情況下。
使用場景:
- 如果項目完全基于Spring框架,那么@Autowired可能是更自然的選擇;
- 而如果是在Java EE環境中,或者你更傾向于通過名稱來引用bean,那么@Resource可能更適合。
參數
- @Autowired 支持一個 required 參數,默認值為 true。設置為 false 時,表示即使沒有找到對應的bean也不會報錯。
- @Resource 支持 name 和 type 屬性,可以明確指定要注入的bean的名稱和類型。
注入方式
- @Autowired 支持構造器注入、設值方法注入以及字段注入。
- @Resource 主要用于字段注入和設值方法注入,不直接支持構造器注入。
四 構造器注入
在 Spring 框架中,構造器自動注入(Constructor Injection)?是一種通過類的構造方法(Constructor)自動注入依賴項的方式。它不僅是依賴注入(DI)的核心模式之一,更是 Spring 官方推薦的最佳實踐。以下是其核心概念、優勢及使用場景的詳細解析:
1.?什么是構造器注入?
-
定義:通過類的構造方法參數傳遞依賴項,由 Spring 容器自動將匹配的 Bean 注入到參數中。
-
自動注入:從 Spring 4.3 開始,如果類只有一個構造方法,
@Autowired
?注解可以省略,Spring 會默認使用該構造方法注入依賴。
@Service
public class UserService {private final UserRepository userRepository;private final EmailService emailService;// Spring 自動注入依賴(無需 @Autowired)public UserService(UserRepository userRepository, EmailService emailService) {this.userRepository = userRepository;this.emailService = emailService;}
}
2、構造器注入的優勢
1.?依賴不可變性
-
final
?字段:依賴項通過構造方法賦值后,可以聲明為?final
,確保對象初始化后不可變。 -
線程安全:避免依賴在運行時被意外修改,提升代碼健壯性。
2.?明確依賴關系
-
強制依賴:構造方法參數明確聲明了類的所有必需依賴,避免依賴缺失。
-
啟動時檢查:如果 Spring 容器中缺少某個依賴,應用會在啟動時直接報錯(而非運行時才暴露問題)。
3.?避免循環依賴
-
設計約束:如果兩個類通過構造器注入相互依賴,Spring 會直接拋出?
BeanCurrentlyInCreationException
,迫使開發者重構代碼,解決循環依賴問題。
4.?更好的測試性
-
無需容器:在單元測試中,可以直接通過構造方法傳入 Mock 對象,無需依賴 Spring 容器或反射。
-
代碼透明:依賴關系一目了然,便于理解類的職責。
3、使用場景
1.?強依賴場景
-
類的核心功能依賴某個組件(如數據庫訪問層?
UserRepository
)。 -
示例:服務類、控制器、數據訪問對象(DAO)。
2.?需要不可變對象的場景
-
配置類、DTO(數據傳輸對象)、工具類等,確保依賴不會被修改。
3.?Spring Boot 項目
-
Spring Boot 強烈推薦構造器注入,尤其是在結合 Lombok 的?
@RequiredArgsConstructor
?時,可以大幅簡化代碼。
4、實現方式
1.?隱式自動注入(Spring 4.3+)
-
如果類只有一個構造方法,Spring 會自動選擇它進行注入,無需?
@Autowired
。
@Service
public class PaymentService {private final PaymentGateway paymentGateway;// 無需 @Autowiredpublic PaymentService(PaymentGateway paymentGateway) {this.paymentGateway = paymentGateway;}
}
2.?顯式指定構造方法
-
如果類有多個構造方法,需用?
@Autowired
?指定使用哪一個。
@Service
public class OrderService {private final InventoryService inventoryService;private final Logger logger;@Autowired // 顯式標記要使用的構造方法public OrderService(InventoryService inventoryService) {this(inventoryService, LoggerFactory.getLogger(OrderService.class));}// 輔助構造方法public OrderService(InventoryService inventoryService, Logger logger) {this.inventoryService = inventoryService;this.logger = logger;}
}
3.?結合 Lombok 簡化代碼
-
使用?
@RequiredArgsConstructor
?自動生成包含?final
?字段的構造方法。
@Service
@RequiredArgsConstructor // 自動生成構造方法
public class NotificationService {private final EmailService emailService;private final SmsService smsService;
}