Spring Boot @Service
互相調用全攻略:@Autowired
vs @Resource
在日常寫 Spring Boot 項目的時候,經常會遇到一個問題:多個 @Service
之間需要互相調用,到底該怎么寫才優雅?用 @Autowired
?用 @Resource
?循環依賴怎么辦?
本文就帶你一口氣整清楚,并配合 Demo 來對比,最后還會總結最佳實踐。
1. 基礎:@Service
是什么?
在 Spring 里,@Service
其實就是一個 特殊的 Bean。它被 Spring 容器管理,創建、銷毀、注入都由 Spring 來完成。
所以,不管你用 @Autowired
還是 @Resource
,本質上都是 依賴注入(Dependency Injection)。
2. @Autowired
:Spring 派來的助手
2.1 特點
- 默認按照 類型(byType)注入;
- 如果有多個同類型的 Bean,會報錯,需要用
@Qualifier
指定; - 支持構造器、字段、Setter 注入;
- 可以加
required = false
,讓依賴變成可選。
2.2 Demo
@Service
public class UserService {public String getUserName(Long id) {return "User-" + id;}
}@Service
public class OrderService {private final UserService userService;// 構造器注入(推薦 ?)@Autowiredpublic OrderService(UserService userService) {this.userService = userService;}public void createOrder(Long userId) {System.out.println("訂單用戶: " + userService.getUserName(userId));}
}
3. @Resource
:JDK 官方背書
3.1 特點
- 來自 JSR-250 標準,算是“官方背書”;
- 默認按照 名稱(byName)注入,找不到時再按照類型;
- 常用在字段 / Setter 注入;
- 不支持
required = false
。
3.2 Demo
@Service
public class UserService {public String getUserName(Long id) {return "User-" + id;}
}@Service
public class OrderService {@Resourceprivate UserService userService; // 按字段名 userService 找 Beanpublic void createOrder(Long userId) {System.out.println("訂單用戶: " + userService.getUserName(userId));}
}
3.3 多實現類場景
@Service("vipUserService")
public class VipUserService extends UserService {@Overridepublic String getUserName(Long id) {return "VIP-" + id;}
}@Service
public class OrderService {@Resource(name = "vipUserService")private UserService userService;public void createOrder(Long userId) {System.out.println("訂單用戶: " + userService.getUserName(userId));}
}
4. 循環依賴問題
有時候,你寫著寫著,就會掉進一個坑:兩個 Service 互相依賴。
@Service
public class AService {@Autowiredprivate BService bService;public void a() {System.out.println("A 調用");bService.b();}
}@Service
public class BService {@Autowiredprivate AService aService;public void b() {System.out.println("B 調用");aService.a();}
}
結果:啟動失敗,提示循環依賴。
4.1 循環調用的可視化
4.2 解決方法
- 重構代碼(最佳 ?):抽出公共邏輯放到
CService
,避免直接互調。 - 延遲注入(權宜之計):在其中一個依賴上加
@Lazy
。
@Service
public class BService {private final AService aService;public BService(@Lazy AService aService) {this.aService = aService;}public void b() {System.out.println("B 調用");aService.a();}
}
5. 總結:到底用哪個?
-
單實現類場景:
用@Autowired
或@Resource
都行,推薦 構造器 +@Autowired
。 -
多實現類場景:
@Resource(name="xxx")
更直觀;
@Autowired + @Qualifier("xxx")
也可以。 -
循環依賴:
優先考慮 重構;不得已時用@Lazy
。
6. 最佳實踐建議
-
優先構造器注入,少用字段注入
字段注入雖然寫起來爽,但對測試和維護都不友好。 -
@Autowired
vs@Resource
沒有絕對優劣- 傾向 Spring → 用
@Autowired
; - 傾向標準化 → 用
@Resource
。
- 傾向 Spring → 用
-
不要用循環依賴當“快捷方式”
那通常說明設計有問題。
在
@Autowired
和@Resource
之間糾結,遠不如搞清楚你的代碼結構更重要。
真正能寫好 Service 之間調用的,不是靠注解,而是靠 架構設計。
實用小工具
App Store 截圖生成器、應用圖標生成器 、在線圖片壓縮和 Chrome插件-強制開啟復制-護眼模式-網頁亂碼設置編碼
乖貓記賬,AI智能分類的最佳聊天記賬App。
Elasticsearch可視化客戶端工具