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

【Spring】超详细!一篇文章让你完全理解Spring Ioc和 DI

【Spring】超详细!一篇文章让你完全理解 Spring IoC 和 DI

大家好,我是 Grok。今天我们来聊聊 Spring 框架的核心灵魂——IoC(Inversion of Control,控制反转)DI(Dependency Injection,依赖注入)。如果你是 Spring 小白,或者想彻底搞懂这两个概念,这篇文章绝对够用!我们从基础原理入手,逐步深入到实际代码、配置和高级玩法,保证逻辑清晰、易记。

为什么说“超详细”?因为我会用:

  • 通俗比喻:像“厨师 vs 餐厅老板”来解释抽象概念。
  • 表格对比:快速区分传统方式 vs Spring 方式。
  • 代码示例:Maven + Java 简单项目,复制就能跑。
  • 步骤拆解:从 XML 配置到注解、Java 配置,全覆盖。
  • 常见坑:避免初学者踩雷。

假设你有 Java 基础(类、接口、Maven),没问题就开始吧~

第一部分:基础概念——IoC 和 DI 到底是什么?

1.1 IoC:控制反转(Inversion of Control)

传统编程:你(程序员)像个“厨师”,自己控制一切——创建对象、调用方法、管理依赖。比如,你要一个“汽车”对象,就自己new Car(),然后自己组装轮子、引擎。

IoC 的核心思想:把“控制权”反转给别人(Spring 容器)。你不再自己new对象,而是告诉 Spring:“我需要一个汽车”,Spring 像“餐厅老板”一样,自动帮你组装好、注入依赖、甚至管理生命周期。

  • 为什么需要 IoC?
    传统方式耦合太紧:改一个类,就得改一堆地方。IoC 解耦,让代码更灵活、可测试、可扩展。

  • IoC 的好处(3 大关键词):

    • 解耦:模块间不直接依赖,改动不连锁反应。
    • 复用:对象像“乐高积木”,随时组装。
    • 管理:Spring 统一管理对象创建、销毁、作用域。

IoC 是“思想”,DI 是“实现方式”。IoC 就像“外卖平台”,DI 就像“骑手送餐”。

1.2 DI:依赖注入(Dependency Injection)

DI 是 IoC 的具体实现:Spring 不是让你自己找依赖,而是“注入”给你。

  • 依赖什么?一个对象需要另一个对象才能工作。比如,Car需要EngineWheel
  • 注入怎么做?Spring 通过配置(XML/注解/Java)自动把依赖“塞”进你的对象。

DI 的 3 种方式(按注入时机分):

方式描述优点/缺点示例场景
构造函数注入通过构造方法注入依赖强制依赖(对象创建时就注入),测试友好核心依赖(如数据库连接)
Setter 注入通过 Setter 方法注入灵活(可选依赖),但可能注入不全可选配置(如日志级别)
接口注入通过接口方法注入(较少用)动态,但复杂遗留系统集成

DI 让你的代码从“主动拉取”依赖变成“被动接收”。

1.3 IoC vs DI 的关系(别混淆!)

  • IoC 是大概念:控制反转,包括 DI 和其他(如 AOP)。
  • DI 是 IoC 的子集:具体怎么反转控制?通过注入依赖。
  • Spring 的 IoC 容器:ApplicationContextBeanFactory,管理所有 Bean(对象)。

一句话:IoC 是“老板指挥”,DI 是“老板给你发工具”。

第二部分:Spring 中的 IoC 和 DI 实战

Spring 版本:假设用 Spring Boot 2.7+ 或 Spring Framework 6.x(2026 年主流)。先建个 Maven 项目:

<!-- pom.xml 核心依赖 --><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.0</version><!-- 最新版自行替换 --></dependency></dependencies>

2.1 配置方式 1:XML 配置(经典,但老派)

XML 是 Spring 最早的配置方式,适合理解底层。

步骤拆解

  1. 定义 Bean:XML 文件中声明对象。
  2. 注入依赖:用<property><constructor-arg>
  3. 获取容器:ClassPathXmlApplicationContext加载 XML。

示例代码

  • 接口和类:
publicinterfaceEngine{voidstart();}publicclassPetrolEngineimplementsEngine{publicvoidstart(){System.out.println("Petrol Engine started");}}publicclassCar{privateEngineengine;// 依赖// Setter 注入publicvoidsetEngine(Engineengine){this.engine=engine;}publicvoiddrive(){engine.start();System.out.println("Car is driving");}}
  • XML 配置(applicationContext.xml):
<?xml version="1.0" encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 定义 Bean --><beanid="petrolEngine"class="com.example.PetrolEngine"/><beanid="car"class="com.example.Car"><!-- DI:Setter 注入 --><propertyname="engine"ref="petrolEngine"/></bean></beans>
  • 测试:
publicclassMain{publicstaticvoidmain(String[]args){ApplicationContextcontext=newClassPathXmlApplicationContext("applicationContext.xml");Carcar=(Car)context.getBean("car");// IoC 容器提供car.drive();// 输出: Petrol Engine started \n Car is driving}}

构造函数注入版 XML(替换<property>):

<beanid="car"class="com.example.Car"><constructor-argref="petrolEngine"/></bean>

Car 类加构造:public Car(Engine engine) { this.engine = engine; }

2.2 配置方式 2:注解配置(现代主流,简单)

从 Spring 2.5 开始,注解取代 XML。Spring Boot 默认用这个。

关键注解

注解作用示例
@Component标记类为 Bean(通用)@Component public class Car {}
@Service业务层 Bean@Service
@RepositoryDAO 层 Bean@Repository
@ControllerWeb 层 Bean@Controller
@Autowired自动注入依赖(byType,默认)@Autowired private Engine engine;
@Qualifier指定 Bean 名(当多个同类型时)@Qualifier(“petrol”)
@Configuration配置类(代替 XML)@Configuration public class AppConfig {}
@Bean方法返回 Bean@Bean public Engine engine() {}
@ComponentScan扫描包,自动发现 Bean@ComponentScan(“com.example”)

示例代码(注解版):

  • 类:
@ComponentpublicclassPetrolEngineimplementsEngine{publicvoidstart(){System.out.println("Petrol Engine started");}}@ComponentpublicclassCar{@AutowiredprivateEngineengine;// DI 注入publicvoiddrive(){engine.start();System.out.println("Car is driving");}}
  • 配置类(可选,如果不扫描默认包):
@Configuration@ComponentScan("com.example")// 扫描包publicclassAppConfig{}
  • 测试:
publicclassMain{publicstaticvoidmain(String[]args){ApplicationContextcontext=newAnnotationConfigApplicationContext(AppConfig.class);Carcar=context.getBean(Car.class);car.drive();}}

自动装配模式(@Autowired 的底层):

  • byType:按类型匹配(默认)。
  • byName:按 Bean 名匹配(用 @Qualifier)。

2.3 配置方式 3:Java 配置(纯代码,零 XML/注解污染)

适合大型项目,配置集中。

示例(基于 2.2 的类,去掉 @Component):

@ConfigurationpublicclassAppConfig{@BeanpublicEngineengine(){returnnewPetrolEngine();}@BeanpublicCarcar(){Carc=newCar();c.setEngine(engine());// 手动 DIreturnc;}}

测试同上:new AnnotationConfigApplicationContext(AppConfig.class)

第三部分:高级玩法——Bean 管理和优化

3.1 Bean 作用域(Scope)

默认 Singleton(单例),但可以改。

Scope描述注解/配置
singleton全局唯一实例默认
prototype每次 getBean 都新创建@Scope(“prototype”)
request每个 HTTP 请求一个@Scope(“request”) (Web)
session每个会话一个@Scope(“session”)

示例:@Scope("prototype") public class Car {}

3.2 Bean 生命周期

IoC 容器管理从创建到销毁的全过程:

  1. 实例化(new)。
  2. 属性注入(DI)。
  3. 初始化(@PostConstruct 或 init-method)。
  4. 使用。
  5. 销毁(@PreDestroy 或 destroy-method)。

自定义:

publicclassCar{@PostConstructpublicvoidinit(){System.out.println("Init");}@PreDestroypublicvoiddestroy(){System.out.println("Destroy");}}

3.3 自动装配(Autowiring)

  • @EnableAutoConfiguration(Spring Boot 用):自动配置常见 Bean(如 DataSource)。
  • 问题:多个同类型 Bean?用 @Primary 标记首选,或 @Qualifier 指定。

第四部分:常见问题 & 踩坑指南

问题/坑原因解决
NoSuchBeanDefinitionExceptionBean 未定义或未扫描检查 @Component / @Bean / 扫描包
UnsatisfiedDependencyException依赖未注入检查 @Autowired / 类型匹配
循环依赖A 依赖 B,B 依赖 A用 Setter 注入 / @Lazy 延迟
XML vs 注解性能XML 解析慢优先注解 / Java 配置
测试时注入失败上下文未加载用 @SpringBootTest

调试技巧:日志级别调到 DEBUG,看 Spring 如何装配 Bean。

第五部分:总结 & 扩展学习

  • 核心回顾:IoC 是反转控制,DI 是注入依赖。Spring 通过容器(ApplicationContext)管理 Bean,实现解耦和灵活。
  • 为什么 Spring 牛?因为 IoC/DI 让大型项目像“积木”一样搭建,易维护。
  • 下一步:学 AOP(切面编程),然后 Spring Boot(简化版 Spring)。
  • 练习建议:建个小项目,注入 Service 到 Controller,模拟用户注册。

如果你有具体代码问题、或想看 Spring Boot 版示例,继续问我~比如“帮我写个带数据库的 DI 示例”?😄

http://www.jsqmd.com/news/325469/

相关文章:

  • 基于vue3实施部门权限分配及审批的监管系统-开题报告 黄耀兴202006050071 (2)
  • 图片如何适应容器框
  • Python学习之路-字典(Dictionary)学习详解
  • ‌2026年测试覆盖率作弊检测术终极指南
  • FreqNet-PhysPrognosis:基于频率特性感知和物理机理融合的机械退化趋势预测(Pytorch)
  • 基于Vue技术的营养食品搭配系统的设计与实现任务书
  • Curve+ 5.0.2色彩校准软件下载|Windows 10专用G7+/G7/SCTV/TVI专业校色工具
  • 洛雪音乐 手机版+桌面版+魔改版 | 目前最强免费音乐软件,支持无损下载,IKUN魔改版更新
  • 《节奏医生》核心玩法攻略
  • 办公必备,pdf转word免费高效方法
  • 服务器卡顿之——CPU 性能分析
  • Ubuntu 20.04使用pip安装spyder
  • 收藏备用|2026年AI大模型学习指南(小白+程序员必看,避坑+实操全干货)
  • 最好用的免费pdf转word工具,告别付费会员
  • 采光瓦客户评价影响选购,了解工厂采光瓦基本信息很重要
  • 篷房源头厂家选择哪家好,迈斯特篷房价格贵不贵?
  • 轨迹预测十年演进
  • 必收藏|2026年普通人+程序员,轻松抓住大模型AI红利的5个实操方向(小白友好)
  • 聊聊深圳研究院转让,多少钱能选到靠谱品牌?
  • 工厂采光瓦产品怎么样,普世建材价格和性价比值得考虑吗
  • 2026年河南靠谱的网络科技公司排名,讲讲河南宸辉网络科技合作模式有哪些
  • YOLO26n_车牌识别_数据集(境内 + 16W训练 + 4W验证)
  • 可靠的AI搜索优化品牌企业有哪些,深圳地区推荐盘点
  • 2026年河南舞蹈艺考品牌排名,分析CDC舞蹈艺考师资力量、口碑靠谱吗
  • 硬件在环十年演进
  • 2026年AI搜索优化公司排名,深圳性价比高的推荐
  • 2026年优质的工业级磷酸二氢钠厂家,价格是多少钱
  • 行车控制算法十年演进
  • 环视感知十年演进
  • 行业内服务好的天虹提货券回收平台推荐