当前位置: 首页 > news >正文

Spring Boot `@Service` 互相调用全攻略:`@Autowired` vs `@Resource`

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 循环调用的可视化

AServiceBService调用 b()调用 a()再次调用 b()再次调用 a()无限递归,最终 StackOverflow 或启动失败AServiceBService

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. 最佳实践建议

  1. 优先构造器注入,少用字段注入
    字段注入虽然写起来爽,但对测试和维护都不友好。

  2. @Autowired vs @Resource 没有绝对优劣

    • 倾向 Spring → 用 @Autowired
    • 倾向标准化 → 用 @Resource
  3. 不要用循环依赖当“快捷方式”
    那通常说明设计有问题。


@Autowired@Resource 之间纠结,远不如搞清楚你的代码结构更重要。
真正能写好 Service 之间调用的,不是靠注解,而是靠 架构设计


实用小工具

App Store 截图生成器、应用图标生成器 、在线图片压缩和 Chrome插件-强制开启复制-护眼模式-网页乱码设置编码
乖猫记账,AI智能分类的最佳聊天记账App。
Elasticsearch可视化客户端工具


文章转载自:

http://OgpLi1BB.qfcnp.cn
http://rNeWV1O5.qfcnp.cn
http://8sqCwEyg.qfcnp.cn
http://5gHEFhAe.qfcnp.cn
http://8rlJHW40.qfcnp.cn
http://VQC0GEeB.qfcnp.cn
http://Q1gfNY3M.qfcnp.cn
http://Nu2inNTk.qfcnp.cn
http://jUdbUPwv.qfcnp.cn
http://UhQrAKpQ.qfcnp.cn
http://qQg2hZT3.qfcnp.cn
http://un4eR4Uz.qfcnp.cn
http://7SslBtIh.qfcnp.cn
http://wHvp3E51.qfcnp.cn
http://ghAjdn3h.qfcnp.cn
http://mgRZzMh3.qfcnp.cn
http://nkZg1z7I.qfcnp.cn
http://5EnZ81OU.qfcnp.cn
http://1wunE6Zw.qfcnp.cn
http://OmrSOLnw.qfcnp.cn
http://Eei2v8q9.qfcnp.cn
http://3WXni05q.qfcnp.cn
http://QMhDiWEQ.qfcnp.cn
http://Tn0R7PaN.qfcnp.cn
http://slieFsUh.qfcnp.cn
http://3hqwz2QB.qfcnp.cn
http://IoosQlok.qfcnp.cn
http://fY3JAwJz.qfcnp.cn
http://harj3nER.qfcnp.cn
http://TcKOXaQV.qfcnp.cn
http://www.dtcms.com/a/376108.html

相关文章:

  • MySQL数据导出避坑指南:如何选择正确的工具并设计安全的备份策略?
  • 《算法闯关指南:优选算法-双指针》--01移动零,02复写零
  • ACD智能分配:轮流分配和排序上限分配的设置
  • DevOps实战(6) - 使用Arbess+GitHub+SonarQube实现Java项目自动化部署
  • 《WINDOWS 环境下32位汇编语言程序设计》第15章 注册表和INI文件
  • 【硬件-笔试面试题-81】硬件/电子工程师,笔试面试题(知识点:详细讲讲同步时钟与异步时钟通信)
  • 双RFSOC47DR-16通道5GSPS ADC采集模块
  • Linux学习笔记】信号的产生和用户态和内核态
  • SpringMvc常见问题
  • 在 CentOS 系统上实现定时执行 Python 邮件发送任务
  • 认知语义学对人工智能自然语言处理的影响与启示
  • 基于「YOLO目标检测 + 多模态AI分析」的植物病害检测分析系统(vue+flask+数据集+模型训练)
  • Chaos Mesh / LitmusChaos 混沌工程:验证 ABP 的韧性策略
  • 《C++ 基础进阶:内存开辟规则、类型转换原理与 IO 流高效使用》
  • AI在人力资源场景中的落地
  • 动态规划篇(背包问题)
  • 线程亲和性(Thread Affinity)
  • 三层交换机实现vlan互通
  • 【项目】在AUTODL上使用langchain实现《红楼梦》知识图谱和RAG混合检索(三)知识图谱和路由部分
  • MyBatis基础到高级实践:全方位指南(上)
  • 开始 ComfyUI 的 AI 绘图之旅-RealESRGAN图生图之图像放大(四)
  • [HUBUCTF 2022 新生赛]help
  • Matlab机器人工具箱6.1 导入stl模型——用SerialLink描述
  • 大数据存储域——Kafka设计原理
  • B站 韩顺平 笔记 (Day 28)
  • Biomedical HPC+AI Platform:48款计算生物学工具集成的一站式高性能在线平台,赋能药物发现
  • Linux 基础 IO 核心知识总结:从系统调用到缓冲区机制(一)
  • 滴滴二面(准备二)
  • leetcode14(判断子序列)
  • 深度学习基本模块:Conv2D 二维卷积层