Spring Ioc源码引入:什么是IoC,IoC解决了什么问题

什么是IoC

用一个故事举例:

小陈想开一家咖啡店,于是独自创业。找咖啡豆供应商、买咖啡机、招员工,样样都要自己来。开店成本很高。后来,小陈选择加盟连锁咖啡店。总部帮他对接供应商、提供咖啡机,还负责员工培训。小陈只需按流程做好咖啡服务顾客,经营轻松许多。

独立开店时,小陈事事操心,就像没有 IOC,系统耦合度高,难以维护与扩展。加盟后,总部统一管理资源,小陈专注核心业务,如同引入 IOC,降低耦合度,经营变得高效。

上面的故事你可能还无法对应到程序开发场景中,下面我们进行Java代码模拟

用Java代码模拟:

  1. 没有IOC

如下可以看到构造一个咖啡店,需要依赖服务员、清洁工、咖啡豆供应商、以及咖啡机

所以,当我们需要开一个咖啡店的时候,需要自己处理好这些依赖,对应到下面代码,我们自己找到合适的服务员、清洁工、咖啡豆供应商、以及咖啡机,然后开店:

public class CoffeeShop {
// 服务员
private Waiter waiter;
// 清洁工
private Cleaner cleaner;
// 咖啡豆供应商
private CoffeeBeansSupplier coffeeBeansSupplier;
// 咖啡机
private CoffeeMachine coffeeMachine;
public CoffeeShop(Waiter waiter,
Cleaner cleaner,
CoffeeBeansSupplier coffeeBeansSupplier,
CoffeeMachine coffeeMachine) {
this.waiter = waiter;
this.cleaner = cleaner;
this.coffeeBeansSupplier = coffeeBeansSupplier;
this.coffeeMachine = coffeeMachine;
}
public void saleCoffee() { }
}
public class BootStrap {

    public static void main(String[] args) {

        // 我们自己找到合适的服务员
Waiter waiter = null;
// 我们自己找到合适的清洁工
Cleaner cleaner = null;
// 我们自己找到合适的咖啡供应商
CoffeeBeansSupplier coffeeBeansSupplier = null;
// 我们自己找到合适的咖啡机
CoffeeMachine coffeeMachine = null;
// 开店,构造自己的咖啡店
CoffeeShop cacheShop = new CoffeeShop(waiter, cleaner, coffeeBeansSupplier, coffeeMachine); // 开始售卖咖啡
cacheShop.saleCoffee();
}
}
  1. 具备IOC(以SpringBoot 为例)

首先我们使用Autowired注解来描述CoffeeShop依赖服务员、清洁工、咖啡豆供应商、以及咖啡机

public class CoffeeShop {

    // 表明我们需要服务员
@Autowired
private Waiter waiter;
// 表明我们需要清洁工
@Autowired
private Cleaner cleaner;
// 表明我们需要咖啡供应
@Autowired
private CoffeeBeansSupplier coffeeBeansSupplier;
// 表明我们需要咖啡机器
@Autowired
private CoffeeMachine coffeeMachine; public void saleCoffee() { }
}
@SpringBootApplication
public class BootStrap { public static void main(String[] args) {
// ctx就如同总部
ConfigurableApplicationContext ctx = SpringApplication.run(BootStrap.class, args); // ctx.getBean就如同总部处理好各种依赖(服务员、清洁工、咖啡豆供应商、以及咖啡机) CoffeeShop shop = ctx.getBean(CoffeeShop.class); // 我们可以直接进行开店
shop.saleCoffee();
}
}

再理解IoC:

IOC的全称是Inversion of Control,即控制反转。控制反转,从字面理解,就是控制权的反转。

  • 没有IOC:传统的程序流程是由开发者自己控制的,比如对象A需要对象B,那么A会直接创建B或者通过工厂类获取B的实例。这种情况下,控制权在A手里

  • 有了IOC:而IoC则是将这种控制权交给外部容器或框架,由外部来管理对象的创建和依赖关系。比如,通过依赖注入,对象A不需要自己创建B,而是由外部容器将B注入到A中。这样,控制权就从A转移到了容器,这就是所谓的反转。

不同的理解:有的人也认为是从程序员手里,转移到IOC容器

结合上面的例子:

  • 没有IOC:咖啡店需要的各种依赖,需要小陈自己处理,自己找咖啡豆供应商等等,然后开店

  • 有了IOC:咖啡店的所有配置,由总部这个容器来统一安排

IoC解决了什么问题

IOC(控制反转)主要解决对象间耦合度过高的问题。在传统编程中,对象直接通过new关键字创建依赖对象,导致代码高度耦合,难以维护和扩展。IOC将对象的创建、依赖管理和生命周期交给外部容器,从而解耦组件。

在上面场景中,总部就是我们的IOC容器,它管理了众多不同的咖啡供应商,咖啡机,可以根据你开店的需求,为你的咖啡店进行装配。

  1. 那么现在思考一下如何实现IOC呢?

IOC容器需要给CoffeeShop自动的填充依赖——依赖注入(Dependency Injection, DI)

  1. 何为依赖:

    如果一个对象A缺少另外一个对象B那么将无法工作(方法不可用)那么我们可以说,A依赖B

那么如何实现依赖注入呢?

如何实现IoC or DI

3.1 如何描述依赖

首先需要清楚如何描述依赖

在Java中一般有三种方式:

  1. 字段+注解

    如下面代码中的waiter,标注@Autowired说明这个字段需要进行依赖注入

  2. 构造器

    如下面的构造方法,每一个方法参数都可以视为CoffeeShop在描述自己依赖哪些外部组件

  3. setter方法

如下面的setCleaner,同样是实验@Autowired来说明自己依赖Cleaner

public class CoffeeShop {
@Autowired //字段+注解
private Waiter waiter; private Cleaner cleaner;
private CoffeeBeansSupplier coffeeBeansSupplier;
private CoffeeMachine coffeeMachine; // 构造器
public CoffeeShop(Waiter waiter,
Cleaner cleaner,
CoffeeBeansSupplier coffeeBeansSupplier,
CoffeeMachine coffeeMachine) {
this.waiter = waiter;
this.cleaner = cleaner;
this.coffeeBeansSupplier = coffeeBeansSupplier;
this.coffeeMachine = coffeeMachine;
} @Autowired // setter方法
public void setCleaner(Cleaner cleaner) {
this.cleaner = cleaner;
}
}

当然Spring还可以使用注解和工厂方法,这里为了方便粉丝理解,不做过多扩展。

3.2 如何进行依赖注入

如上,我们完成了描述依赖的过程,那么如何进行依赖注入呢?

在java一般来说有两种方式:反射和生成代码

  1. 反射:

    java提供的反射,允许程序在 运行时 动态地获取类的信息(如类名、方法、字段、注解等),并能直接操作类或对象(如创建实例、调用方法、访问私有字段)

  2. 反射调用方法:可以用于实现基于构造器和setter方法的依赖注入,将依赖项作为参数进行传入,然后反射调用方法即可

  3. 反射访问字段:可以用于实现基于字段的依赖注入,找到匹配要求的对象,反射为字段赋值即可

  4. 生成代码:

    例如 Google 维护Dagger 2 ,会在编译时依赖注入框架,直接通过代码生成实现依赖注入,无需反射或动态代理,启动性能更佳。生成代码的方式在Go语言中运用广泛,主要是Go提供的反射能力没有java那么强大,加上Go强调云原生,对部署速度有较高要求

其中Spring Ioc使用的是反射

Spring Ioc源码学习引入

每个 Spring 开发者都踩过的「坑」


为什么要啃 Spring IoC 源码?

  1. 面试「灵魂拷问」高频区
  • “Spring 如何解决循环依赖?”
  • “BeanFactory 和 ApplicationContext 的区别?”
  • “@Autowired 和 @Resource 注入原理有何不同?”

    绝大部分 Java 高级岗位面试会深挖 Spring 源码实现。 仅靠八股文背诵,难以应对灵活追问。
  1. 日常开发中的「未解之谜」
  • 为什么 @Transactional 注解有时失效?
  • 如何定制 Bean 的生命周期回调?
  • 配置文件加载的优先级到底怎么定?

    源码能让你从「玄学调试」进阶到「精准打击」。
  1. 架构思维跃迁的关键阶梯

    Spring 的设计融合了工厂模式、模板方法、策略模式等经典设计模式,其代码是「教科书级」的架构范本。

    读源码 = 站在巨人肩上,学习如何设计高扩展、低耦合的系统。

>>>点击去关注<<<

Spring Ioc源码引入:什么是IoC,IoC解决了什么问题的更多相关文章

  1. Spring系列(三):Spring IoC源码解析

    一.Spring容器类继承图 二.容器前期准备 IoC源码解析入口: /** * @desc: ioc原理解析 启动 * @author: toby * @date: 2019/7/22 22:20 ...

  2. Spring IOC 源码分析

    Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring 的 IOC 容器.既然大家平时都要用到 Spring,怎么可以不好好了解 Spring 呢?阅读本文 ...

  3. Spring Ioc源码分析系列--Ioc的基础知识准备

    Spring Ioc源码分析系列--Ioc的基础知识准备 本系列文章代码基于Spring Framework 5.2.x Ioc的概念 在Spring里,Ioc的定义为The IoC Containe ...

  4. Spring IOC源码研究笔记(2)——ApplicationContext系列

    1. Spring IOC源码研究笔记(2)--ApplicationContext系列 1.1. 继承关系 非web环境下,一般来说常用的就两类ApplicationContext: 配置形式为XM ...

  5. Spring的IOC源码分析

    Spring IOC 容器源码分析 Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring 的 IOC 容器.既然大家平时都要用到 Spring,怎么可以不 ...

  6. Spring IoC源码解析——Bean的创建和初始化

    Spring介绍 Spring(http://spring.io/)是一个轻量级的Java 开发框架,同时也是轻量级的IoC和AOP的容器框架,主要是针对JavaBean的生命周期进行管理的轻量级容器 ...

  7. [spring源码学习]六、IOC源码-BeanFactory和factory-bean

    一.代码实例 在我们分析spring的IOC源码的时候,发现除了配置标准的bean,并且通过getBean(beanName)的方法获取到一个bean的实例外,似乎还有这不少其他获取的方法,例如在第四 ...

  8. Spring:源码解读Spring IOC原理

    Spring IOC设计原理解析:本文乃学习整理参考而来 一. 什么是Ioc/DI? 二. Spring IOC体系结构 (1) BeanFactory (2) BeanDefinition 三. I ...

  9. 深入Spring IOC源码之ResourceLoader

    在<深入Spring IOC源码之Resource>中已经详细介绍了Spring中Resource的抽象,Resource接口有很多实现类,我们当然可以使用各自的构造函数创建符合需求的Re ...

  10. 框架源码系列六:Spring源码学习之Spring IOC源码学习

    Spring 源码学习过程: 一.搞明白IOC能做什么,是怎么做的  1. 搞明白IOC能做什么? IOC是用为用户创建.管理实例对象的.用户需要实例对象时只需要向IOC容器获取就行了,不用自己去创建 ...

随机推荐

  1. clickhouse 为什么如此快及优化

    一.clickhouse 为什么如此快 1)优秀的代码,对性能的极致追求 clickhouse 是 CPP 编写的,代码中大量使用了 CPP 最新的特性来对查询进行加速. 2)优秀的执行引擎以及存储引 ...

  2. FreeSql学习笔记——9.延时加载

    前言   使用过EF都知道延时加载,延时加载即需要用到数据的时候才去数据库读取数据,这样做的好处是只有诗句真正被用到的时候才会执行sql语句读取数据库数据,避免了加载不去要的数据,同时也提升了数据度的 ...

  3. nginx 简单实践:Web 缓存【nginx 实践系列之三】

    〇.前言 本文为 nginx 简单实践系列文章之二,主要简单实践了两个内容:正向代理.反向代理,仅供参考. 关于 Nginx 基础,以及安装和配置详解,可以参考博主过往文章: https://www. ...

  4. 面试必备!HR面常问的20个问题及高分回答秘诀

    HR面试一般会花大约20分钟,主要会问一些个人情况.处理事情的方法.工作经验.成长经历等相关问题. 当你到了HR面,基本上就代表你的面试已经通过了一大半了.不过,还是不要掉以轻心,HR面还是有可能会挂 ...

  5. ctfshow web入门 文件包含全部wp

    Web78 <?php if(isset($_GET['file'])){ $file = $_GET['file']; include($file); }else{ highlight_fil ...

  6. DeepSeek本地性能调优

    技术背景 大模型性能调优是一个很复杂的工程,涉及到很多细节,如果真要对模型动刀子,还需要对模型和数据集本身有非常好的理解.这里我们仅仅考虑模型加载过程中,可以优化的一些参数配置.关于DeepSeek在 ...

  7. MONGODB数据备份与导入

    主要记录下在mongo 3.0的操作 备份示例 ./mongodump -h localhost -d liongo -o ./ 还原示例 错误方式: ./mongorestore -h 127.0. ...

  8. idea中启动web、jsp项目

    1. idea打开项目 选择要打开的项目的根目录 2. 项目配置 配置jdk modules配置 添加web 添加依赖 删除爆红的依赖 添加依赖目录或者jar 配置web.xml 配置lib 如果没有 ...

  9. Codeforces Round 1006 (Div. 3) 比赛记录

    Codeforces Round 1006 (Div. 3) 比赛记录 比赛链接 这场的题目名称都很长啊~. 很简单的一场(毕竟是div3,能不简单嘛)赛时切掉了A - F,C题花的时间有点多,G题偶 ...

  10. FastAPI路由:微服务架构下的路由艺术与工程实践 🌐

    title: FastAPI路由专家课:微服务架构下的路由艺术与工程实践 date: 2025/3/4 updated: 2025/3/4 author: cmdragon excerpt: 用API ...