第73篇:Spring IoC容器(2026版)

📌 系列导航《Java 100 天进阶之路》完整目录 |
⬅️ 上一篇:第72篇:JavaWeb面试高频题 |
➡️ 下一篇:第74篇:Bean生命周期

🗺️ 本文阅读地图(3 分钟速览)

第72篇完成了JavaWeb专题的收官,本篇正式开启 Spring全家桶专题。Spring是Java后端开发的事实标准,而IoC容器是Spring最核心的基石——理解了IoC容器,就理解了Spring的"心脏":

Spring全家桶专题持续推进,拿下AOP!

《Java 100 天进阶之路 | 从入门到上岗就业》 每天一篇,建议收藏 + 关注,一起100天拿offer!

👉 点击关注我,更新后第一时间收到推送!

模块核心问题一句话回答
IoC是什么控制反转到底反转了什么?对象的创建权从"自己new"反转给"容器管理"
DI是什么依赖注入和IoC什么关系?DI是IoC的具体实现方式——容器把依赖"注入"给对象
BeanFactory vs ApplicationContext两个容器有什么区别?BeanFactory是"基础款"(懒加载),ApplicationContext是"旗舰款"(预加载+企业级功能)
Bean是什么Spring里的Bean到底是什么?被Spring IoC容器管理的Java对象
Bean生命周期Bean从生到死经历什么?实例化→属性填充→初始化→使用→销毁
三种配置方式怎么告诉Spring要管理哪些对象?XML配置、注解配置、Java配置(@Configuration + @Bean
面试最爱问高频考点有哪些?见文末 面试小节

一、核心知识点

1. IoC是什么?

IoC(Inversion of Control,控制反转)是一种设计原则,用于减少代码间的直接依赖关系。其核心思想是:将对象的创建、依赖管理等控制权从业务代码转移到外部容器。

💡 通俗理解:传统编程中,调用者主动创建和管理被调用者的生命周期——你需要什么,自己new一个。IoC模式下,你只需要声明"我需要什么",容器会帮你创建好并"注入"进来。

2. DI是什么?

DI(Dependency Injection,依赖注入)是IoC的具体实现方式。对象只通过构造函数参数、工厂方法参数或属性来定义它们的依赖项,容器在创建Bean时注入这些依赖。

💡 核心关系IoC是一种思想,DI是实现这种思想的技术手段

3. IoC解决了什么问题?

问题传统方式IoC方式
耦合度高类内部直接new依赖对象,换实现要改代码依赖通过构造函数/Setter传入,换实现不改代码
难以测试依赖硬编码,无法Mock依赖可替换,单元测试容易
难以扩展新增功能要改已有代码通过配置/注解扩展,符合开闭原则

4. IoC的三大优势

优势说明
解耦性对象间的依赖关系通过容器配置而非硬编码实现
可测试性依赖注入使得单元测试可以通过Mock对象轻松完成
可配置性Bean的创建和装配过程可以通过配置文件或注解灵活调整

二、通俗讲解(1分钟开心学)

把IoC容器想象成"智能工厂 + 配送中心"

本系列第68篇讲过,Servlet容器(Tomcat)是"后厨"。Spring IoC容器比它更进了一步——它不只是"后厨",而是整条供应链的智能管理中心

  • 传统方式(自己new) :你想做一道菜,得自己种菜、自己养猪、自己磨调料——所有依赖都得自己搞定。
  • IoC方式(容器管理) :你只需要告诉工厂"我要做宫保鸡丁",工厂自动把鸡肉、花生、干辣椒配齐送到你手上——你只管炒菜。

两个容器的比喻

  • BeanFactory:小区楼下的自动售货机——你要什么,投币才出货(懒加载),功能单一。
  • ApplicationContext大型仓储超市——一开门就把所有货品都摆好(预加载),还提供推车、导购、退换货等全套服务(事件、国际化、AOP等)。

三、Spring IoC容器体系

3.1 容器层级关系

Spring的IoC容器以 BeanFactory 为顶层接口,ApplicationContext 是其子接口:

在这里插入图片描述

org.springframework.beansorg.springframework.context 包是Spring Framework IoC容器的基础。

3.2 BeanFactory vs ApplicationContext

这是Spring面试100%会问的对比题。

对比维度BeanFactoryApplicationContext
官方定位最基础的IoC容器接口,定义Bean管理的核心规范BeanFactory的子接口,增加了企业级功能
加载策略懒加载——调用getBean()时才创建实例预加载——启动时一次性创建所有单例Bean
核心功能只提供getBean()等基础功能继承BeanFactory全部功能 + 10大扩展功能
实际使用几乎见不到每天都用——SpringApplication.run(...)返回的就是它
常用实现DefaultListableBeanFactoryAnnotationConfigApplicationContextClassPathXmlApplicationContext

ApplicationContext比BeanFactory多出的核心功能

功能说明
事件发布与监听ApplicationEvent + @EventListener
国际化(i18n)MessageSource支持多语言
资源加载ResourceLoader支持classpath:file:
环境抽象Environment + @Profile支持多环境配置
AOP自动代理自动识别@Aspect并织入,@Transactional直接生效
Web应用支持WebApplicationContext

💡 记忆口诀BeanFactory是"基础款"(够用但简陋),ApplicationContext是"旗舰款"(功能全、体验好) 。实际项目100%用ApplicationContext

3.3 Bean是什么?

在Spring中,构成应用程序骨架并由Spring IoC容器管理的对象称为Bean。Bean是由Spring IoC容器实例化、组装和管理的对象。

💡 本质:Bean就是一个普通的Java对象,唯一特殊之处在于——它由Spring容器管理,而不是你自己new出来的。

四、Bean生命周期(5阶段)

Bean的生命周期是Spring面试的必考项,需要掌握以下核心阶段:

在这里插入图片描述

初始化阶段详解(这是生命周期中最复杂的阶段):

步骤说明
① Aware接口回调BeanNameAwareBeanFactoryAware
② BeanPostProcessor前置处理初始化前的拦截
InitializingBean.afterPropertiesSet()接口方式初始化
④ 自定义init-methodXML或注解指定的初始化方法
⑤ BeanPostProcessor后置处理初始化后的拦截,AOP代理在此完成

五、三种Bean配置方式

容器通过读取配置元数据来获取指令——告诉它要实例化哪些对象、如何装配它们。配置元数据可以用三种方式表达:

5.1 XML配置(传统方式)
<!-- applicationContext.xml -->
<beans>
    <bean id="userService" class="com.example.UserServiceImpl">
        <property name="userDao" ref="userDao"/>
    </bean>
    <bean id="userDao" class="com.example.UserDaoImpl"/>
</beans>
// 加载XML配置
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService service = ctx.getBean("userService", UserService.class);
5.2 注解配置(主流方式)
@Service  // 声明为业务层Bean
public class UserServiceImpl implements UserService {
    @Autowired  // 自动注入依赖
    private UserDao userDao;
}

@Repository  // 声明为数据访问层Bean
public class UserDaoImpl implements UserDao {
    // 数据访问逻辑
}
// 启动容器(Spring Boot自动完成)
ApplicationContext ctx = new AnnotationConfigApplicationContext("com.example");

💡 注解含义@Component 是通用注解,@Service@Repository@Controller 是其特化版本,分别用于业务层、数据层和控制层。

5.3 Java配置(@Configuration + @Bean
@Configuration  // 声明这是一个配置类
public class AppConfig {
    
    @Bean  // 方法返回值会被注册为Spring容器中的Bean
    public UserService userService(UserDao userDao) {
        return new UserServiceImpl(userDao);
    }
    
    @Bean
    public UserDao userDao() {
        return new UserDaoImpl();
    }
}
// 加载Java配置
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);

💡 @Configuration原理:配置类会经过ConfigurationClassPostProcessor(后置处理器)处理,解析所有@Bean方法并转换为Bean定义。@Configuration类本身也会被注册为容器中的一个Bean。

六、避坑要点

错误/误区后果正确做法
混淆IoC和DI的概念面试答非所问IoC是思想,DI是实现方式
认为new出来的对象也是Bean容器无法管理,依赖注入失效只有容器创建和管理的对象才是Bean
误以为项目用的是BeanFactory对容器能力理解有偏差实际项目100%用ApplicationContext
不知道@Configuration@Component的区别配置类被代理,行为异常@Configuration是配置类(Full模式),@Component是普通组件
在Bean的构造函数中做耗时操作容器启动变慢耗时操作放到@PostConstructafterPropertiesSet

七、面试高频考点

Q1:IoC和DI是什么关系?

IoC(控制反转)是一种设计思想——将对象的创建和依赖管理的控制权从代码转移到容器。DI(依赖注入)是IoC的具体实现方式——对象通过构造函数参数、工厂方法参数或属性来定义依赖,容器在创建Bean时注入这些依赖。IoC是"理念",DI是"做法"

Q2:BeanFactory和ApplicationContext的区别?

BeanFactory是Spring最基础的IoC容器接口,采用懒加载策略,只提供getBean()等基础功能。ApplicationContext是BeanFactory的子接口,采用预加载策略——启动时一次性创建所有单例Bean,还额外提供了事件发布、国际化、资源加载、AOP集成等企业级功能。实际项目100%用ApplicationContext

Q3:Spring Bean的生命周期有哪些阶段?

五个阶段:①实例化——容器通过反射调用构造函数创建实例;②属性填充——通过依赖注入设置属性值;③初始化——执行Aware回调、BeanPostProcessor前置处理、afterPropertiesSet、自定义init-method、BeanPostProcessor后置处理;④使用——Bean被应用程序调用;⑤销毁——容器关闭时按相反顺序触发销毁逻辑。

Q4:@Configuration@Bean的作用是什么?

@Configuration标记在类上,声明这是一个配置类,相当于XML配置文件。@Bean标记在配置类的方法上,指示该方法返回的对象应该被注册为Spring容器中的Bean。配置类会经过ConfigurationClassPostProcessor处理,将@Bean方法转换为Bean定义。

Q5:Spring支持哪几种Bean配置方式?

三种:①XML配置——传统的<bean>标签方式;②注解配置——通过@Component@Service@Autowired等注解;③Java配置——通过@Configuration + @Bean。现代Spring Boot项目以注解配置Java配置为主。

🎤 面试官追问陷阱(加分题)

追问1:“@Configuration标注的类和@Component标注的类有什么区别?”

👉 @Configuration类会被Spring动态代理,保证其中@Bean方法调用时返回的是容器中已存在的Bean实例(保证单例)。而@Component标注的普通类不会被代理。简单说:@Configuration是"Full模式"(Bean之间调用走代理),@Component是"Lite模式"(不走代理)

追问2:“ApplicationContext启动时做了什么事?能简单说下流程吗?”

👉 核心是refresh()方法。主要步骤:①创建并准备BeanFactory;②读取配置元数据(XML/注解/Java配置),生成BeanDefinition;③注册BeanPostProcessor;④初始化所有非懒加载的单例Bean;⑤发布上下文就绪事件。这就是为什么ApplicationContext启动比BeanFactory慢——它把活都提前干完了。

八、练习题

  1. 简答题:请用自己的话解释IoC和DI的关系。

  2. 代码题:使用@Configuration + @Bean方式,配置一个DataSource Bean和一个UserDao Bean,UserDao依赖DataSource

  3. 分析题:某Spring Boot项目启动非常慢,经排查发现启动时创建了大量Bean。请分析可能的原因,并给出优化建议。

📊 你的学习进度

  • 当前:第73篇 / 共108篇 · 进阶篇:Spring全家桶(第73~82篇)
  • ✅ 已完成:基础篇44篇 + 第45~73篇
  • 📖 正在学:第73篇
  • ⏳ 待学习:第74~108篇

👉 📚 完整目录 & 学习指南 | 🔥 订阅本专栏,不错过每一篇

👉 下一篇文章预告

🚀 下一篇:《第74篇:Bean生命周期

内容简介:Bean生命周期完整15步详解、BeanPostProcessor原理、InitializingBean@PostConstruct执行顺序、销毁流程、扩展点实战。

👉 Spring全家桶专题持续推进,深入Bean生命周期!

📌 《Java 100 天进阶之路 | 从入门到上岗就业》 每天一篇,建议收藏 + 关注,一起100天拿offer!
👉 点击关注我,更新后第一时间收到推送!

更多推荐