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

Spring IoC:彻底搞懂控制反转

控制反转(IoC)。这是一个听起来很高大上、很抽象,但实际上非常朴实和重要的概念。

一、核心思想:一句话概括

控制反转(IoC)是一种软件设计原则,其核心思想是:将对象的创建、依赖装配和生命周期管理的控制权,从应用程序代码中“反转”到一个外部容器(例如 Spring 框架)来负责。

简单说,就是 “别new了,我来给你”


二、通过一个比喻来理解:传统方式 vs. IoC方式

想象一下你去餐厅吃饭:

1. 传统开发方式(控制正转):
  • 你(应用程序代码) 说:“我想吃牛排”。
  • 然后你自己 去菜市场买牛肉、买调料、生火、自己煎牛排、自己摆盘。
  • 你控制了整个过程, tightly coupled(紧耦合),非常麻烦,而且一旦想吃猪排,所有流程都得重来。
// 类似于传统代码:自己在内部创建所有依赖
public class MyService {// 自己创建依赖对象private MyRepository myRepository = new MyRepository();public void doBusiness() {myRepository.queryData();}
}

问题MyService 牢牢控制着 MyRepository 的创建。如果想换一个 NewRepositoryImpl,就必须修改 MyService 的源代码。这违反了“开闭原则”。

2. IoC方式:
  • 你(应用程序代码) 说:“我想吃牛排”。
  • 服务员(IoC容器) 听到后,直接通知后厨做好一份标准的牛排,然后端给你(注入给你)
  • 你不需要关心牛排是怎么来的,你只负责吃(使用)就行了。控制权从“你”反转到了“餐厅系统”。
// 使用IoC的代码:依赖由外部容器提供(注入)
public class MyService {// 不自己创建,只声明一个依赖private MyRepository myRepository;// 容器通过这个构造方法将MyRepository“注入”进来public MyService(MyRepository myRepository) {this.myRepository = myRepository;}public void doBusiness() {myRepository.queryData();}
}

好处MyService 不再关心 MyRepository 是谁实现的、怎么创建的。它只依赖于 MyRepository 这个抽象(接口)。之后你想换一种 MyRepository 的实现,根本不需要改动 MyService 的代码,只需要告诉容器(通过配置)用什么实现就行了。这就是 “松耦合”


三、IoC 和 DI(依赖注入)是什么关系?

这是一个非常常见的疑问。

  • IoC(控制反转):是一个广义的概念,一种设计思想。它描述了“控制权被反转”这一现象。实现IoC思想有很多种方式,例如:

    • 模板方法模式(Template Method)
    • 服务定位器模式(Service Locator)
    • 依赖注入(Dependency Injection)
  • DI(依赖注入):是实现IoC最常用、最主流的一种技术手段。它特指“通过外部将依赖对象注入到组件中”的这种具体做法。

所以,可以这样理解:

IoC 是目的(目标),DI 是手段(实现方式)。

Spring 框架通过 DI 这种方式来实现 IoC 思想。因此,我们平时在 Spring 中所说的 IoC,实际上指的就是 DI。


四、依赖注入(DI)的几种方式

Spring 容器负责创建 Bean(对象),并注入它们的依赖。主要有三种注入方式:

1. 构造器注入(推荐的方式
@Component
public class MyService {private final MyRepository myRepository;// 容器会自动找到MyRepository的实例,并通过构造器注入进来@Autowired // Spring 4.3 后,如果只有一个构造器,@Autowired可省略public MyService(MyRepository myRepository) {this.myRepository = myRepository;}
}

优点

  • 保证依赖不可变(final 关键字)。
  • 保证依赖不为空(null)。
  • 完全初始化的状态,更安全。
2. Setter 方法注入
@Component
public class MyService {private MyRepository myRepository;// 容器会通过调用这个setter方法进行注入@Autowiredpublic void setMyRepository(MyRepository myRepository) {this.myRepository = myRepository;}
}

优点:可选依赖或需要重新配置依赖时比较灵活。

3. 字段注入(不推荐用于主要业务代码
@Component
public class MyService {@Autowired // 直接注入到字段上private MyRepository myRepository;
}

缺点

  • 绕过构造方法,可能导致依赖不为空(null)的假设失效。
  • 让代码与Spring框架紧密耦合(因为直接用了@Autowired注解)。
  • 无法设置final字段,对象状态可能可变。
  • 不利于单元测试(你必须通过反射来注入依赖)。

现代最佳实践是使用构造器注入。


五、Spring IoC 容器是什么?

Spring IoC 容器就是这个“餐厅系统”/“服务员”。它的核心是 ApplicationContext 接口。

它的工作流程:

  1. 配置元数据:你通过 XML、Java 配置或注解(如 @Component, @Service, @Repository)告诉容器:“请管理这些类”。
  2. 启动容器:容器启动后,会根据配置信息创建并组装好所有对象(这些对象被称为 Bean),放在一个“池子”里。
  3. 等待索取/注入:当你的应用程序需要某个 Bean 时(比如通过 @Autowired),容器会自动将它已经创建好的那个对象“注入”到需要的地方。

总结:为什么使用IoC?(优点)

  1. 降低耦合度:组件不关心依赖的具体实现,只关心接口。代码变得灵活,易于维护和扩展。
  2. 提高可测试性:可以轻松地将真实依赖替换为 Mock对象 进行单元测试。例如,给 MyService 注入一个假的 MyRepository 来测试业务逻辑。
  3. 管理生命周期:容器可以统一管理对象的生命周期(如初始化、销毁)。
  4. 集中配置:所有对象的创建和组装逻辑都集中在容器中,而不是散落在代码的各个角落,更易于管理。

总而言之,IoC 是一种让代码变得更灵活、更松散耦合、更易于测试的强大设计思想,而 Spring 框架通过依赖注入(DI)完美地实现了它。 你不再是自己“new”对象的苦力,而是变成一个“提出需求”,由容器(Spring)来满足的架构师。


文章转载自:

http://bjWRrNtu.nxtgb.cn
http://TFMmU9Ap.nxtgb.cn
http://6dhkh3Pr.nxtgb.cn
http://6jjOmD54.nxtgb.cn
http://5c32cBZD.nxtgb.cn
http://iK9CmkgG.nxtgb.cn
http://VHBmk0kN.nxtgb.cn
http://5X4R5fxY.nxtgb.cn
http://XVh9imKA.nxtgb.cn
http://wQZjxbsF.nxtgb.cn
http://AENBbCNR.nxtgb.cn
http://iFyp5HK1.nxtgb.cn
http://7ngiePLN.nxtgb.cn
http://yeEVWrcs.nxtgb.cn
http://fReoHBCf.nxtgb.cn
http://qwDdL0he.nxtgb.cn
http://7PoQ8iOx.nxtgb.cn
http://2w1aYGW8.nxtgb.cn
http://P2FFTVg0.nxtgb.cn
http://2YUHKzG5.nxtgb.cn
http://gyLxH8YI.nxtgb.cn
http://YRZoHhqy.nxtgb.cn
http://5KLhK78R.nxtgb.cn
http://mx094czn.nxtgb.cn
http://I2fpDpX9.nxtgb.cn
http://ydo4UVti.nxtgb.cn
http://drMd7VcH.nxtgb.cn
http://3mPocWMh.nxtgb.cn
http://iBzbbi81.nxtgb.cn
http://qqmp7tg0.nxtgb.cn
http://www.dtcms.com/a/374651.html

相关文章:

  • SLAM(同步定位与建图)
  • Cursor 编辑器:面向 AI 编程的新一代 IDE
  • 数字图像处理-设计生成一个半球
  • Web 前端可视化开发工具对比 低代码平台、可视化搭建工具、前端可视化编辑器与在线可视化开发环境的实战分析
  • 计算机网络---网络体系结构
  • java day18
  • RIP协议
  • 什么是双ISP住宅IP
  • 权限即数据:企业系统中的字段级访问控制架构实战(β=0.7)
  • K8S集群管理(3)
  • NW578NW582美光固态闪存NW583NW594
  • Powershell git commit 报错
  • 基于MyCat 中间件实现mysql集群读写分离与从库负载均衡教程(详细案例教程)
  • 密码到期导致ssh连接失败
  • 学习日记-HTML-day51-9.9
  • 硬件开发2-汇编2(ARMv7-A)
  • 基于mybatis-plus动态数据源实现mysql集群读写分离和从库负载均衡教程(详细案例)
  • Elasticsearch面试精讲 Day 14:数据写入与刷新机制
  • TDengine 选择函数 LAST_ROW() 用户手册
  • Flink 状态管理的核心能力
  • Hive实战(三)
  • git无法拉去远程仓库-connection reset
  • 计算机毕设推荐:基于Hadoop+Spark物联网网络安全数据分析系统 物联网威胁分析系统【源码+文档+调试】
  • 使用 BERT 实现意图理解和实体识别
  • QB/T 4674-2021 汽车内装饰用聚氨酯束状超细纤维合成革检测
  • spark11-sparkSQL 实现wordcount
  • 微硕双N-MOS管WST3392在汽车智能氛围灯系统中的应用
  • 小鹏汽车 vla 算法最新进展和模型结构细节
  • SpringBoot多场景中23种常用注解详解
  • 复杂PDF文档结构化提取全攻略——从OCR到大模型知识库构建