一篇文章让你彻底吃透 Spring 核心:从概念到面试,建议收藏(2026年4月版)

小编 应用案例 2

一、开篇引入:为什么 Spring 是每个 Java 开发者绕不开的必修课?

在 Java 企业级开发领域,Spring 框架几乎无处不在。无论是初学 Java 的新人,还是正在备战面试的求职者,亦或是需要深入理解技术原理的资深工程师,Spring 都是一个绕不开的“必学知识点”。根据 2025 年 Stack Overflow 开发者调查数据,Spring Boot 在所有 Web 框架中的使用率约为 14.7%,并获得高达 53.7% 的开发者好评-

一篇文章让你彻底吃透 Spring 核心:从概念到面试,建议收藏(2026年4月版)-第1张图片

很多开发者在学习和使用 Spring 时普遍存在一个痛点:会用但不懂原理。不少人能用 @Autowired 注入依赖、用 @Transactional 实现事务管理,但面试官追问“IoC 容器是怎么创建 Bean 的?”“AOP 的动态代理有哪两种方式?”时就难以回答-2。IoC 和 DI 的区别、AOP 的应用场景、Spring Boot 与传统 Spring 的差异等概念也常被混淆。

本文将从 痛点切入 → 核心概念 → 代码示例 → 底层原理 → 高频面试题 这条主线,由浅入深地带你彻底吃透 Spring 的核心知识体系。无论你是技术入门者、在校学生,还是正在备战面试的求职者,相信本文都能帮你理清逻辑、看懂示例、记住考点。

一篇文章让你彻底吃透 Spring 核心:从概念到面试,建议收藏(2026年4月版)-第2张图片

二、痛点切入:传统开发方式到底有什么问题?

在理解 Spring 的设计初衷之前,我们先来看一段传统的 Java 代码:

java
复制
下载
// 传统方式:直接在代码中 new 依赖对象
public class OrderService {
    private OrderDao orderDao = new OrderDaoImpl();
    private EmailService emailService = new EmailServiceImpl();

    public void createOrder(Order order) {
        orderDao.insert(order);
        emailService.send(order.getUserEmail(), "订单创建成功");
    }
}

这段代码存在几个典型问题:

  • 高耦合:OrderService 直接依赖了 OrderDaoImpl 和 EmailServiceImpl 的具体实现类,一旦实现类发生变化,OrderService 的代码也必须修改。

  • 扩展性差:假设需要将 EmailServiceImpl 替换为另一个实现(比如切换邮件服务商),必须修改 OrderService 的源代码。

  • 测试困难:单元测试时无法方便地注入 Mock 对象,测试必须依赖真实的 Dao 和邮件服务实现。

  • 代码冗余:每个需要依赖其他对象的类都需要重复编写 new 实例的代码。

这种传统开发模式催生了 Spring 框架的核心设计理念——控制反转(IoC)与依赖注入(DI)。Spring 正是为了解耦对象之间的强依赖关系而诞生的。

三、核心概念讲解:IoC(控制反转)

标准定义

IoC(Inversion of Control,控制反转) 是一种设计思想,其核心是:将对象的创建、配置和生命周期管理交给外部容器来完成,而不是由程序代码主动控制--42

关键词拆解

  • “控制” :指的是对象的创建权、依赖管理权、生命周期管理权。

  • “反转” :将这些控制权从程序代码(开发者)手中,转移到外部容器(Spring IoC 容器)手中-

生活化类比

如果把 Spring 比作一家公司,IoC 容器就像是这家公司的“人力资源部” 。人力资源部负责招聘员工(创建对象)、分配岗位(管理依赖)、安排离职(管理生命周期)。作为“业务部门”的开发者,只需要告诉 HR“我需要一个什么样的人”,而不需要自己去招聘、培训、发工资——这些繁琐的事情全部由 HR 部门搞定-1

解决的问题

IoC 主要解决了传统开发中的高耦合问题。当对象的控制权交给容器后,组件之间不再直接持有强引用,而是由容器在运行时动态注入依赖,从而极大降低了代码耦合度,提升了系统的可扩展性和可测试性-11

四、关联概念讲解:DI(依赖注入)

标准定义

DI(Dependency Injection,依赖注入) 是 IoC 的具体实现方式。它指的是容器在创建对象的过程中,自动将被依赖的对象“注入”到目标对象中-12

DI 与 IoC 的关系(核心考点)

一句话总结:IoC 是一种思想,DI 是实现这种思想的具体手段。 -12

很多初学者会混淆这两个概念,其实它们是从不同角度描述同一个事情:

  • IoC 强调“控制权的反转” —— 谁说了算的问题。

  • DI 强调“依赖如何传递” —— 具体怎么给的问题。

用类比来理解:IoC 是“把做饭的权力交给厨房”,而 DI 是“厨房通过什么方式把做好的菜端给你”——可以是服务员端过来(构造器注入)、自己去窗口取(Setter 注入)、或者直接放桌上(字段注入)。

Spring 中 DI 的三种实现方式

注入方式示例代码特点
构造器注入(推荐)@Autowired public UserService(UserDao userDao) { this.userDao = userDao; }依赖不可变,便于测试,保证依赖完整性
Setter 注入@Autowired public void setUserDao(UserDao userDao) { this.userDao = userDao; }可选依赖,可动态修改
字段注入(最常用但不推荐)@Autowired private UserDao userDao;写法简单,但不利于测试且容易违反单一职责原则-53

声明 Bean 的常用注解

将对象交给 Spring IoC 容器管理,只需在类上添加对应注解:

  • @Controller / @RestController:Controller 层

  • @Service:Service 业务层

  • @Repository:DAO 数据访问层

  • @Component / @Configuration:通用组件或配置类-11

依赖注入时,使用 @Autowired(Spring 原生,默认按类型注入)或 @Resource(JDK 提供,默认按名称注入)-56

五、概念关系与区别总结

对比维度IoC(控制反转)DI(依赖注入)
性质设计思想 / 设计原则具体实现技术
关注点“控制权归谁”“依赖怎么给”
层次理念层(Why)实现层(How)
类比“要开公司,权力交给 HR”“HR 通过面试流程招人”

记忆口诀:IoC 是思想,DI 是手段;思想定方向,手段来落地。

六、代码示例:从传统开发到 Spring IoC/DI

6.1 传统方式(痛点回顾)

java
复制
下载
// 业务类 - 手动创建依赖
public class UserServiceImpl implements UserService {
    private UserDao userDao = new UserDaoImpl();  // 硬编码依赖

    public void findAll() {
        userDao.query();
    }
}

6.2 Spring IoC/DI 方式(注解配置)

java
复制
下载
// 步骤1:定义依赖类,交给 Spring 管理
@Repository
public class UserDaoImpl implements UserDao {
    public void query() {
        System.out.println("查询用户数据...");
    }
}

// 步骤2:业务类,通过 @Autowired 注入依赖
@Service
public class UserServiceImpl implements UserService {
    @Autowired   // Spring 自动注入依赖
    private UserDao userDao;

    public void findAll() {
        userDao.query();   // 直接使用,无需手动创建
    }
}

// 步骤3:启动 Spring 容器
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(Application.class, args);
        UserService userService = context.getBean(UserService.class);
        userService.findAll();
    }
}

6.3 关键改进点说明

对比项传统方式Spring IoC/DI 方式
对象创建开发者手动 new容器自动创建
依赖管理硬编码写死@Autowired 动态注入
耦合度高(依赖具体实现类)低(依赖接口 + 容器解耦)
可测试性难(无法 Mock)易(可注入 Mock 对象)

执行流程说明:Spring 容器启动时,会扫描带有 @Service@Repository 等注解的类,将它们实例化并存入 IoC 容器。当遇到 @Autowired 注解时,容器会根据类型(或名称)从容器中找到对应的 Bean 并自动注入到目标对象中。

七、AOP(面向切面编程)—— Spring 的另一大支柱

7.1 什么是 AOP?

AOP(Aspect-Oriented Programming,面向切面编程) 是 Spring 框架的另一核心特性,用于将横切关注点(cross-cutting concerns) 从业务逻辑中分离出来,实现代码的解耦和复用-25

7.2 典型应用场景

场景说明
日志记录在方法执行前后自动记录日志,无需每个方法手动添加
事务管理声明式事务管理,通过 @Transactional 自动控制事务
权限校验在方法执行前统一进行权限检查
性能监控统计方法执行耗时,发现性能瓶颈
统一异常处理全局捕获异常并统一处理

7.3 AOP 核心术语

术语英文解释
切面Aspect横切逻辑的模块化封装(通常是一个带 @Aspect 的类)
通知Advice切面执行的具体动作(前置、后置、环绕等)
切点Pointcut匹配连接点的表达式,决定通知织入到哪些方法
连接点Join Point可以插入通知的点(如方法执行)
织入Weaving将切面应用到目标对象并创建代理对象的过程

7.4 简单示例:记录方法执行时间

java
复制
下载
@Aspect
@Component
public class LoggingAspect {

    // 定义切点:匹配 com.example.service 包下所有类的所有方法
    @Pointcut("execution( com.example.service..(..))")
    public void serviceMethods() {}

    // 环绕通知:记录方法执行时间
    @Around("serviceMethods()")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();  // 执行目标方法
        long elapsedTime = System.currentTimeMillis() - start;
        System.out.println(joinPoint.getSignature() + " 执行耗时:" + elapsedTime + "ms");
        return result;
    }
}

八、Spring Boot:让 Spring 开发更简单

8.1 传统 Spring 开发的痛点

在 Spring Boot 出现之前,使用 Spring 开发需要大量繁琐的 XML 配置:配置数据源、配置事务管理器、配置视图解析器……一个简单的 Web 项目往往需要上百行配置代码-33

8.2 Spring Boot 的解决方案

Spring Boot 是基于 Spring Framework 的快速开发脚手架,其核心理念是 “约定优于配置”(Convention over Configuration) --33

特性说明
自动配置根据 classpath 中的依赖自动配置 Spring Bean
起步依赖(Starter)预封装的依赖集合,一键引入相关功能
嵌入式服务器内置 Tomcat/Jetty,java -jar 直接运行
生产就绪Actuator 提供健康检查、指标监控等运维功能

效率提升数据:相较于传统 Spring 框架,Spring Boot 在开发效率上可提升 40%~60%。某大型电商平台重构案例显示,采用 Spring Boot 后项目启动时间从 12 分钟缩短至 45 秒,配置文件数量减少 75%-32

8.3 Spring、Spring MVC、Spring Boot 三者的关系

  • Spring:核心框架,提供 IoC、AOP、事务管理等基础能力。

  • Spring MVC:Spring 框架中的一个模块,专门用于构建 Web 应用-56

  • Spring Boot:基于 Spring 的快速开发工具,简化配置和部署,不是替代 Spring,而是让 Spring 开发更便捷。

8.4 Spring Boot 自动配置原理(面试高频)

@SpringBootApplication 注解是三个注解的组合-1-54

text
复制
下载
@SpringBootApplication = @SpringBootConfiguration + @ComponentScan + @EnableAutoConfiguration

其中 @EnableAutoConfiguration 是自动配置的核心:Spring Boot 启动时会扫描 classpath 中 META-INF/spring.factories(Spring Boot 2.7+ 为 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports)文件,根据条件注解(如 @ConditionalOnClass)判断是否加载对应的自动配置类-32

九、底层原理支撑:IoC 容器是如何工作的?

9.1 IoC 容器的两大核心接口

接口特点使用场景
BeanFactory懒加载,轻量级Spring 底层基础设施
ApplicationContext非懒加载,功能更丰富日常开发使用

ApplicationContext 是 BeanFactory 的子接口,扩展了国际化、事件传播、资源加载等功能。常用实现类有 AnnotationConfigApplicationContext(注解配置)和 ClassPathXmlApplicationContext(XML 配置)-41

9.2 IoC 容器底层实现原理

Spring IoC 容器的底层实现核心是 工厂模式 + 反射机制-42-41

简化版执行流程

  1. 加载配置元数据:读取配置文件或扫描注解,收集需要被 Spring 管理的类。

  2. 解析为 BeanDefinition:将每个类的元信息(类名、作用域、依赖关系等)封装为 BeanDefinition 对象-41

  3. 实例化:通过反射调用构造器创建对象实例-

  4. 依赖注入:根据配置将依赖的对象注入到实例中。

  5. 初始化:执行 Aware 接口回调、BeanPostProcessor 处理、@PostConstruct 等方法-1

  6. 使用与销毁:Bean 投入使用,容器关闭时执行销毁回调。

9.3 Bean 的生命周期(核心 5 阶段)

text
复制
下载
实例化 → 属性注入 → 初始化 → 使用中 → 销毁
  • 实例化:通过反射创建对象

  • 属性注入:注入 @Autowired 标记的依赖

  • 初始化:执行 Aware 接口 → BeanPostProcessor 前置 → @PostConstruct/init-method → BeanPostProcessor 后置(AOP 代理通常在此生成)

  • 使用中:Bean 提供服务

  • 销毁:执行 @PreDestroy/destroy-method-1-53

十、高频面试题与参考答案

面试题 1:谈谈你对 Spring IoC 和 DI 的理解,它们有什么区别?

参考答案

IoC(Inversion of Control,控制反转)是一种设计思想,核心是将对象的创建、依赖管理、生命周期管理等控制权从程序代码转移到外部容器(Spring IoC 容器)。DI(Dependency Injection,依赖注入)是实现 IoC 的具体技术手段,容器在创建对象时将依赖对象自动注入进来。

两者的核心区别:IoC 是思想,DI 是具体实现。IoC 回答“谁说了算”,DI 回答“具体怎么给”-12

面试题 2:Spring 支持哪几种依赖注入方式?官方推荐哪种?

参考答案

Spring 支持三种依赖注入方式:

  1. 构造器注入:通过构造方法注入依赖(官方推荐)

  2. Setter 注入:通过 setter 方法注入

  3. 字段注入:直接在字段上使用 @Autowired(写法简单但不推荐)

推荐构造器注入的原因:保证依赖完整性(避免 NPE)、便于单元测试、支持不可变对象、符合单一职责原则-53-56

面试题 3:Spring AOP 的底层实现原理是什么?JDK 动态代理和 CGLIB 有什么区别?

参考答案

Spring AOP 底层基于动态代理实现,根据目标类的情况选择两种代理方式:

  • JDK 动态代理:基于接口实现,要求目标类必须实现至少一个接口。

  • CGLIB 代理:基于字节码生成子类实现,不需要接口。Spring 4+ 默认使用 CGLIB-25-1

对比项JDK 动态代理CGLIB
前提条件目标类必须实现接口无接口要求
实现原理反射 + Proxy 类字节码生成子类
性能略低略高
final 方法无影响无法代理 final 方法

面试题 4:@Transactional 事务在哪些情况下会失效?

参考答案(常见失效场景):

  1. 方法非 public:Spring 事务默认只对 public 方法生效。

  2. 同类中自调用:同类内通过 this 调用方法,事务注解不生效(因为走的是本类实例而非代理对象)。

  3. 异常被 try-catch 捕获且未重新抛出:Spring 事务默认只在运行时异常(RuntimeException)时回滚-

  4. 数据库引擎不支持事务:如 MySQL 的 MyISAM 引擎不支持事务-

  5. 事务传播机制配置错误:如 REQUIRES_NEW 等传播行为可能导致预期外的行为-

面试题 5:Spring Boot 的自动配置是如何实现的?

参考答案

Spring Boot 的自动配置基于 @EnableAutoConfiguration 注解实现。核心流程:

  1. Spring Boot 启动时,@SpringBootApplication 注解中的 @EnableAutoConfiguration 触发自动配置机制。

  2. Spring 加载 classpath 中 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中定义的所有自动配置类。

  3. 自动配置类中使用条件注解(如 @ConditionalOnClass@ConditionalOnMissingBean)判断是否生效。

  4. 根据判断结果,动态创建相应的 Bean 并注册到 IoC 容器中-32-54

十一、结尾总结

核心知识点回顾

本文从传统开发痛点出发,系统讲解了 Spring 框架的核心知识体系:

  • IoC(控制反转) :一种设计思想,将对象控制权交给容器——思想层面

  • DI(依赖注入) :IoC 的具体实现,通过三种注入方式完成依赖传递——实现层面

  • AOP(面向切面编程) :将横切关注点从业务代码中剥离,实现统一管理

  • Spring Boot:基于“约定优于配置”简化 Spring 开发,大幅提升开发效率

  • 底层原理:工厂模式 + 反射实现 IoC 容器,动态代理实现 AOP

重点与易错提醒

  1. IoC 和 DI 不要混淆:IoC 是思想,DI 是实现,面试必考点。

  2. 事务失效场景要记住:自调用、非 public、异常被吞是三大高频坑。

  3. 注入方式尽量用构造器:字段注入虽然方便,但不推荐在生产代码中使用。

  4. Spring Boot ≠ Spring:Spring Boot 是简化工具,底层依然是 Spring Framework。

下一站预告

Spring 的知识体系远不止本文所讲的内容。下一篇将深入探讨 Spring 事务传播机制与源码分析,从 7 种传播行为的底层实现原理,到 Spring 事务拦截器的源码解析,再到生产环境中的最佳实践,帮助你彻底吃透 Spring 事务管理的每一个细节。敬请期待!


本文首发于 2026 年 4 月,基于 Spring 6.x / Spring Boot 3.x 主流版本编写。如有疑问或建议,欢迎在评论区交流讨论。

抱歉,评论功能暂时关闭!