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
java
@Service
public class UserService {
public String getUserName(Long id) {
return "User-" + id;
}
}
@Service
public class OrderService {
private final UserService userService;
// 构造器注入(推荐 ✅)
@Autowired
public 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
java
@Service
public class UserService {
public String getUserName(Long id) {
return "User-" + id;
}
}
@Service
public class OrderService {
@Resource
private UserService userService; // 按字段名 userService 找 Bean
public void createOrder(Long userId) {
System.out.println("订单用户: " + userService.getUserName(userId));
}
}
3.3 多实现类场景
java
@Service("vipUserService")
public class VipUserService extends UserService {
@Override
public 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 互相依赖。
java
@Service
public class AService {
@Autowired
private BService bService;
public void a() {
System.out.println("A 调用");
bService.b();
}
}
@Service
public class BService {
@Autowired
private AService aService;
public void b() {
System.out.println("B 调用");
aService.a();
}
}
结果:启动失败,提示循环依赖。
4.1 循环调用的可视化
AService BService 调用 b() 调用 a() 再次调用 b() 再次调用 a() 无限递归,最终 StackOverflow 或启动失败 AService BService
4.2 解决方法
- 重构代码 (最佳 ✅):抽出公共逻辑放到
CService
,避免直接互调。 - 延迟注入 (权宜之计):在其中一个依赖上加
@Lazy
。
java
@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可视化客户端工具