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

Spring Framework 入门第一天:掌握核心容器 IOC 与 DI

前言

在 2026 年的 Java 开发世界里,Spring Boot 已经成为了事实上的标准。我们铺天盖地的项目、微服务、中间件,底层都离不开 Spring 的支撑。为了不“浮沙筑高台”,我们非常有必要深入底层,把 Spring Framework 这个地基打牢。

今天我们开启 Spring 全家桶学习的第一站:Spring Framework。先整体看看它的架构,再深入理解它最核心的两个思想:IOC(控制反转)DI(依赖注入),最后手写代码配置出第一个 Spring 容器。

💬课前摸底:你在平时写代码时,是不是经常遇到“改了一个类名,结果关联的地方要改一堆”的情况?有没有想过如何让程序“解耦”?在评论区说说你对“耦合”的痛恨程度!

一、什么是 Spring?一张图看懂它的家族

目前我们要掌握的 Spring 全家桶主要包含三部分:

  1. Spring Framework:底层核心框架(我们今天学这个)。
  2. Spring Boot:对 Spring 的封装简化,开箱即用。
  3. Spring Cloud:分布式微服务解决方案。

Spring Framework 的五层架构

从 Spring 4 开始,整体架构大致分为五层,从底向上依次是:

层级模块核心作用
1. 核心层 (Core)Core ContainerSpring 最底层核心,其他所有层都依赖它。
2. AOP 层AOP, Aspects面向切面编程,在不改变原代码前提下增强功能。
3. 数据层 (Data)Data Access, Integration, Transactions负责数据库访问、事务管理。
4. Web 层Web, Servlet (Spring MVC)处理 Web 请求,MVC 模式实现(后续重点)。
5. 测试层 (Test)Test整合 Junit,支持单元测试、集成测试。

🧠AOP 小提示:OOP 是面向对象,AOP 则是面向方法(切面)。目前只需要知道它是用来“加功能”的即可,后面会细讲。

二、Spring 核心概念:别再自己 new 对象了!

在没有框架的时候,我们写 Java Web 项目,业务层(Service)要调数据层(Dao),是不是只能private BookDao bookDao = new BookDaoImpl();

这会导致一个巨麻烦的问题:高耦合。一旦BookDaoImpl改了名或换了实现类,所有引用它的 Service 你都得改一遍代码。我们追求的“高内聚、低耦合”瞬间崩塌。

为了解决这个痛点,Spring 提出了IOC思想,并且用IOC 容器把这个思想实现了。

2.1 IOC(控制反转)

思想定义:把对象的创建控制权从程序内部,反转给外部容器来管理。

  • 以前:你自己做饭吃(主动 new 对象)。
  • 现在:你点外卖(向 IOC 容器要对象)。

简单来说:你的代码里不再需要new对象,需要什么找容器拿就行。

2.2 IOC 容器 与 Bean

Spring 实现 IOC 的做法是搞一个“大池子”,专门负责创建和管理对象。

  • IOC 容器:这个管理对象的大池子。
  • Bean:容器里存放的每一个对象,就叫做 Bean。

2.3 DI(依赖注入)

容器里既有BookService的 Bean,也有BookDao的 Bean。但是,BookService想要调用BookDao,容器怎么知道它们俩有关系呢?

这时候就需要DI(依赖注入)了。它的作用就是建立 Bean 与 Bean 之间的绑定关系

  • 以前:Service 自己找 Dao。
  • 现在:Service 跟容器喊一声:“喂,给我注入一个 Dao 用用!”,容器就把 Dao 的 Bean 塞给 Service,这就是依赖注入。

✍️动笔理一理:IOC 是思想(控制权反转),DI 是手段(注入依赖关系)。容器是 IOC 思想的产物,Bean 是容器里的物件。这几个概念的关系你厘清了吗?

三、手把手:从底层玩转 Spring IOC

别看 Spring Boot 里写个@Autowired就搞定了,底层 Spring Framework 其实是通过配置文件完成的。跟着我做,体会一把“从底抄”的感觉。

3.1 第一步:创建 Maven 项目,加依赖

pom.xml加入核心依赖spring-context和测试依赖junit

<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.10.RELEASE</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency></dependencies>

3.2 第二步:准备基础代码

分别创建数据层(Dao)和业务层(Service)的接口及实现类。

// 数据层接口publicinterfaceBookDao{voidsave();}// 数据层实现类publicclassBookDaoImplimplementsBookDao{publicvoidsave(){System.out.println("book dao save ...");}}// 业务层接口publicinterfaceBookService{voidsave();}// 业务层实现类(注意这里依然有 new,我们马上解决它)publicclassBookServiceImplimplementsBookService{// 目前还是手动 new,耦合度高,第三步会优化privateBookDaobookDao=newBookDaoImpl();publicvoidsave(){System.out.println("book service save ...");bookDao.save();}}

3.3 第三步:配置 Spring 配置文件(核心)

resources目录下新建applicationContext.xml,把刚才那些类“托付”给 Spring 的 IOC 容器,让容器帮我们管理。

<?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标签:把一个类声明为受Spring管理的Bean --><!-- id:必须唯一,是这个Bean在容器里的唯一标识 --><!-- class:你这个类的全限定名 --><beanid="bookDao"class="com.itheima.dao.impl.BookDaoImpl"/><beanid="bookService"class="com.itheima.service.impl.BookServiceImpl"/></beans>

⚠️切记:在同一个配置文件中,Bean 的id不能重复,必须唯一。

3.4 第四步:启动容器,获取对象

在主类中,通过ClassPathXmlApplicationContext加载配置文件,获取 IOC 容器,然后从容器里拿 Bean 来用。

publicclassApp{publicstaticvoidmain(String[]args){// 1. 加载配置文件,初始化IOC容器ApplicationContextctx=newClassPathXmlApplicationContext("applicationContext.xml");// 2. 从容器中根据id获取BeanBookServicebookService=(BookService)ctx.getBean("bookService");// 3. 调用方法bookService.save();}}

运行一下,成功输出!但你会发现,此时业务层的代码里依然用new创建了 Dao 对象,耦合问题并没有彻底解决。

四、进阶:用 DI 彻底消灭 new

光把对象放进 IOC 容器不够,我们还要让容器帮我们把对象“组装”起来。

操作步骤:

  1. 清空:删除BookServiceImpl中的private BookDao bookDao = new BookDaoImpl();
  2. 留门:给BookServiceImpl提供BookDaosetter方法。
  3. 配置:在 XML 中告诉 Spring,bookService里的bookDao,帮它注入对应的 Bean。

修改后的BookServiceImpl

publicclassBookServiceImplimplementsBookService{// 不再自己new,只定义属性privateBookDaobookDao;// 提供setter方法,Spring靠这个注入publicvoidsetBookDao(BookDaobookDao){this.bookDao=bookDao;}publicvoidsave(){System.out.println("book service save ...");bookDao.save();}}

修改后的applicationContext.xml配置(DI 注入部分):

<beanid="bookDao"class="com.itheima.dao.impl.BookDaoImpl"/><beanid="bookService"class="com.itheima.service.impl.BookServiceImpl"><!-- 配置依赖注入 --><!-- property:给当前Bean的某个属性赋值 --><!-- name:填属性的名字(比如 bookDao),Spring会自动找到 setBookDao() 方法 --><!-- ref:填注入哪个 Bean 的 id --><propertyname="bookDao"ref="bookDao"/></bean>

知识点辨析:

  • property中的name:对应BookServiceImpl里的变量名bookDao。Spring 拿到这个名字后,会首字母大写+补set,变成setBookDao,然后去调用这个方法给你注入。
  • property中的ref:指向<bean id="bookDao" .../>那个 Bean 的名字。

🎯动手挑战:把你的applicationContext.xml里的<property name="bookDao" ref="bookDao"/>,不看笔记自己敲一遍。然后试着把ref随便改个不存在的名字(比如bookDao2),再运行看看会报什么错?把报错信息发在评论区,我们一起分析!

五、总结

今天我们初探了 Spring Framework,需要重点掌握:

  1. Spring 架构:五层结构,核心层是根基。
  2. IOC(控制反转):把 new 对象的权利交给 Spring 容器。
  3. DI(依赖注入):通过setter方法 + XML 配置,把容器中 Bean 的依赖关系组装起来。
  4. Bean 配置三要素id(唯一标识)、class(全限定类名)、property(依赖注入)。

今天我们依然保留了 Service 中的 setter 注入,这比直接 new 前进了一大步,但代码写起来还是有点繁琐。下一期,我们会继续深入 Spring 的 DI,讲讲除了setter注入以外,还有哪些更便捷的玩法!

📝课后作业:不看代码,能说出 IOC 和 DI 分别解决了什么问题吗?用你自己的话把它们的核心区别写下来,加深理解。在评论区打卡,我会挑出最通俗易懂的解释置顶!


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

相关文章:

  • 从汽车设计到游戏建模:B样条曲线是如何成为工业软件‘隐形冠军’的?
  • DistroAV终极指南:如何在MacOS上快速解决OBS-NDI插件问题
  • 新手别怕!用IDA Pro分析CTF PWN栈溢出题,保姆级实战复盘(附Python脚本)
  • 别只做线性回归了!用SPSS曲线估计与Logistic回归,挖掘数据中的非线性关系与分类规律
  • SQL Developer 连接类型 (Connection Type) :SID 和 Service Name的区别
  • 大语言模型幻觉问题解析与抗幻觉技术实践
  • Windows WSL环境搭建OpenClaw机器人开发环境全攻略
  • 终极英雄联盟回放分析工具:5步掌握ROFL播放器的完整使用指南
  • 别再让GPU内存浪费了!用vLLM的PagedAttention技术,让你的LLaMA推理吞吐量提升24倍
  • 自动化发布流程:使用skill-release-cop实现CI/CD版本管理
  • Python股票诊断工具:基于开源库构建自动化基本面分析框架
  • 梦笔记20260507
  • Vue3项目实战:Element Plus表格拖拽排序的‘坑’我都帮你踩完了(SortableJS集成指南)
  • 智能体输入编译器:将自然语言转化为结构化指令的工程实践
  • 手把手教你用ArduPilot飞控,让DIY的F450四轴在无GPS下也能稳如老狗(Kakute F7 AIO实战)
  • 5分钟掌握Windows风扇控制:Fan Control终极免费散热优化指南
  • 基于Matplotlib的学术论文图表标准化绘制与自动化工作流实践
  • LLM智能体调试框架AgentDebug核心技术解析
  • VoiceClaw开源项目:为本地AI模型构建安全语音交互接口
  • 后端开发中的安全防护策略:防范常见攻击
  • android使用C++交叉编译opencv转换图片示例
  • MIMIGenRec:基于GAN与VAE的数据生成与识别重建框架实战
  • 初次使用 Taotoken 从注册到发出第一个 API 请求的全流程
  • Ruby 运算符
  • Stencil计算在Tensor Cores上的性能优化实践
  • 别再被‘must have the same language type’报错卡住!详解Uniapp中<script>与<script setup>共存的正确姿势
  • 不止于消失:深入挖掘Unity Dissolve特效在技能、场景过渡中的高级应用
  • 树莓派AI开发套件Ubo Pod:开源智能助手全解析
  • AI智能体技能库构建指南:从模块化设计到工程实践
  • Windows Defender完全移除指南:3种模式深度解析与实战教程