【个人学习||spring】

Spring 系统学习手册

目标:用最短时间掌握 Spring 最重要、最常用、最有实战价值的 80% 内容,达到"能理解、能解释、能上手、能排错、能通过基础到中级面试"的程度。

学习对象:默认你是初学者,但我们会把深度拉到中级工程师能解释原理、能排查问题的层次。

学习原则:先直觉,后定义;先主干,后展开;先能跑,后深挖;先工程常用,后冷门细节。

学习地图

1. 这门学科是干什么的

Spring 是 Java 生态里最核心的企业级开发框架之一。它本质上不是"一个单点技术",而是一套围绕企业应用开发建立起来的编程模型。

它最核心的价值有四个:

  1. 管对象:把对象的创建、依赖关系、生命周期交给容器统一管理。
  2. 解耦合:业务代码只关心"我要什么依赖",而不是"我怎么 new 出来它"。
  3. 统一基础能力:事务、日志、权限、缓存、配置、事件、Web 请求处理都能统一接入。
  4. 提升工程效率:配合 Spring Boot,可以快速搭建可运行、可配置、可测试、可部署的服务。

一句话理解:

Spring = 用"容器 + 约定 + 扩展点"来组织 Java 企业应用。

2. 它解决什么问题

如果没有 Spring,企业开发会遇到这些典型问题:

问题 不用 Spring 时会怎样 Spring 怎么解决
对象依赖复杂 代码里到处 new,模块强耦合 用 IoC 容器统一创建 Bean
横切逻辑重复 每个方法都手写事务、日志、鉴权 用 AOP 统一织入
Web 请求处理混乱 Servlet 层样板代码多 用 Spring MVC 统一处理请求
配置难管理 环境差异、硬编码、切环境困难 application.yml、Profile、配置绑定
测试困难 对象关系复杂,Mock 难写 容器化管理,方便替换和注入
工程规范难统一 团队项目结构不一致 Spring Boot 形成事实标准

3. 它和哪些相关技术有关系

Spring 不是孤立存在的,它和下面这些技术高度关联:

技术 关系 学 Spring 时需要掌握到什么程度
Java 基础 Spring 的载体 必须吃透:面向对象、接口、泛型、注解、反射基础
Maven / Gradle 依赖管理和构建 必须会基本用法
HTTP / Servlet Spring MVC 的基础 至少理解请求-响应模型
JSON Web 接口交互常态 必须会
JDBC / MyBatis / JPA 数据访问 至少会一种
Spring Boot Spring 的工程化入口 必须掌握
Tomcat / Undertow Web 容器 知道作用即可
AOP / 动态代理 Spring 核心机制之一 必须吃透
事务 企业开发高频能力 必须吃透
Redis / MQ / Security 常见企业扩展 先知道,后深入

4. 学它之前需要哪些前置知识

建议你至少具备下面这些基础:

  1. Java 面向对象:类、接口、继承、多态。
  2. Java 常用语法:集合、异常、泛型、枚举、Lambda 基本理解。
  3. 注解基础:知道注解是什么、为什么有运行期注解。
  4. 反射基础:至少知道可以通过反射拿类、方法、字段。
  5. Maven:会加依赖、跑项目、看依赖树。
  6. HTTP:知道 GET/POST、请求头、状态码、JSON。
  7. 数据库基础:会写基本 SQL,知道事务是什么意思。

如果这些还不稳,不用暂停学 Spring,但要边学边补。

5. 真正重要的 20% 核心内容是什么

必须吃透:这部分决定你能不能真正理解 Spring。

  1. IoC 和 DI:为什么对象要交给容器管理。
  2. Bean:Bean 是什么、怎么注册、怎么注入、生命周期是什么。
  3. ApplicationContext:容器到底做了什么。
  4. AOP 和代理:为什么事务、日志、权限能"自动生效"。
  5. @Transactional:什么时候生效,为什么有时会失效。
  6. Spring MVC:一次 HTTP 请求在 Spring 里怎么走。
  7. Spring Boot 自动配置:为什么"引个 starter 就能用"。
  8. 常见排错:Bean 注入失败、配置不生效、事务失效、请求 404/405/415。

如果你把这 8 件事吃透,Spring 面试和项目开发的 80% 问题你都能接住。

6. 哪些内容是初学者容易陷入、但不值得一开始深挖的

先知道,后深入:不要一上来把时间耗在"有技术味但暂时不产出"的地方。

  1. 过早深挖全部源码。
  2. XML 配置的所有细节。
  3. 很少用的 Bean Scope 和冷门扩展点。
  4. Spring 所有事件机制、资源加载细节。
  5. WebFlux / Reactor 全家桶。
  6. Spring Security OAuth2 的完整协议细节。
  7. Native Image、AOT、GraalVM。
  8. 各种"背诵型八股",但没有工程场景支撑。

7. 学习本质

学 Spring,不是背注解。

真正要学的是三层东西:

  1. 思想层:控制反转、约定优于配置、面向接口、扩展点设计。
  2. 机制层:容器如何建对象图,代理如何织入横切逻辑,Web 请求如何分发。
  3. 工程层:如何把这些机制落成可维护、可排错、可测试的项目。

如果你只会写 @Service@Autowired,你只是"会用";

如果你能解释 Bean 生命周期、事务为什么失效、自动配置为什么生效,你才是真正掌握。

8. 设计哲学

Spring 的设计哲学可以概括为:

  1. 把重复的基础工作收编到框架层。
  2. 让业务代码面向抽象,不面向创建细节。
  3. 用元数据驱动行为:注解、配置、条件装配。
  4. 用扩展点而不是硬编码来支持变化。

业务代码声明依赖
Spring 容器解析配置
创建 Bean
注入依赖
织入事务 / 日志 / 权限
对外提供 Web / Service 能力

学习顺序

正确顺序:先把主干跑通,再补底层;先会解释,再会扩展;先能定位问题,再追源码。

  1. 先认识 Spring 全家桶,分清 Spring、Spring MVC、Spring Boot 分别干什么。
  2. 学 IoC / DI / Bean / 容器,这是整个 Spring 的根。
  3. 学 Bean 生命周期、配置方式、依赖注入规则。
  4. 学 AOP、动态代理、事务机制。
  5. 学 Spring MVC 请求处理流程。
  6. 学 Spring Boot 自动配置、配置文件、Profile、Starter。
  7. 学工程实践:分层、校验、异常处理、日志、测试、配置管理。
  8. 学排错:Bean 问题、事务问题、请求问题、配置问题。
  9. 最后再系统整理面试答法、源码切入点和项目实战。

推荐学习节奏

阶段 目标 结果
第 1 阶段 建立整体认知 知道 Spring 为什么存在、核心模块是什么
第 2 阶段 理解核心概念 会解释 Bean、容器、依赖注入
第 3 阶段 掌握核心机制 会解释 AOP、事务、MVC 流程
第 4 阶段 连接到底层原理 会解释代理、生命周期、刷新流程
第 5 阶段 落地工程实践 能写一个像样的 Spring Boot 服务
第 6 阶段 具备排错能力 能定位高频错误
第 7 阶段 形成面试表达 能回答基础到中级问题
第 8 阶段 闭环与进阶 知道下一步该学什么

初学者最容易学偏的地方

  1. 只记注解,不懂容器。
  2. 只会 CRUD,不会解释事务和 AOP。
  3. 直接背源码流程图,但写不出工程代码。
  4. 把 Spring Boot 当成 Spring 全部。
  5. 遇到问题只会改配置,不会看日志、断点、定位链路。

必须掌握 vs 知道即可

层次 必须掌握 知道即可
概念 IoC、DI、Bean、AOP、事务、MVC、Boot 自动配置 资源加载、事件广播、冷门 Scope
工程 分层、配置、异常处理、校验、日志、测试 自定义复杂 Starter、AOT
原理 动态代理、Bean 生命周期、事务代理链 所有源码类名与调用细节
面试 概念 + 原理 + 场景 + 常见坑 冷门扩展点背诵

第一阶段:入门认知

1. 学什么

这一阶段只做一件事:建立 Spring 的整体认知。

你要搞清楚:

  1. Spring 到底是什么,不是什么。
  2. Spring 解决了企业开发中的哪些痛点。
  3. Spring、Spring MVC、Spring Boot 之间是什么关系。
  4. 为什么企业项目几乎都会用 Spring 体系。

2. 为什么重要

如果一开始没有全景视角,后面你会很容易出现两种偏差:

  1. 把 Spring 当成"注解大全"。
  2. 把 Spring Boot 当成"黑盒启动器"。

第一阶段的价值,不是写很多代码,而是先搭好脑中的框架。

只有你先知道整个系统的骨架,后面每一个概念才有位置,不会碎片化。

3. 它解决什么实际问题

Spring 最初流行起来,是因为它把企业 Java 开发中最痛的几件事同时解决掉了:

  1. 对象创建混乱:谁依赖谁、何时创建、如何替换,交给容器统一管理。
  2. 业务代码被样板逻辑污染:事务、日志、权限这类横切逻辑不用每个方法都手写。
  3. Web 开发太重:从低层 Servlet 升级到统一的 MVC 编程模型。
  4. 工程启动太慢:配合 Spring Boot 后,项目可以快速搭起来,配置更收敛。

4. 核心概念定义

先用类比理解。

把 Spring 想成一家"工厂 + 调度中心":

  1. 你不自己招人组装团队,而是把岗位要求交给工厂。
  2. 工厂负责招人、分配工位、建立协作关系。
  3. 你只负责告诉工厂:"订单服务需要库存服务、支付服务。"

技术定义:

概念 直觉理解 技术定义
Spring 企业开发工具箱 一套用于构建 Java 企业应用的基础框架体系
IoC 不自己管对象 对象控制权从业务代码转交给容器
DI 自动配齐依赖 容器在创建对象时把依赖注入进去
Bean 被容器接管的对象 由 Spring 管理生命周期和依赖关系的对象
容器 总调度中心 通常指 ApplicationContext
Spring MVC Web 请求调度层 Spring 里的 Web MVC 框架
Spring Boot 快速工程化入口 基于 Spring 的约定式启动与自动配置框架

Spring、Spring MVC、Spring Boot 的关系

名称 关注点 你应该怎么理解
Spring Framework 基础框架 核心容器、AOP、事务、MVC 等能力来源
Spring MVC Web 模块 处理 HTTP 请求、参数绑定、返回结果
Spring Boot 工程化加速器 帮你更快把 Spring 项目跑起来

一句话:

Spring 是底座,Spring MVC 是 Web 模块,Spring Boot 是工程化加速器。

5. 工作流程或运行机制

先看最粗的运行流程:

  1. 应用启动。
  2. Spring 创建容器。
  3. 容器扫描配置类和组件。
  4. 容器创建 Bean 并注入依赖。
  5. Web 项目则继续初始化 MVC 相关组件。
  6. 业务代码通过容器拿到对象开始工作。

如果是 Web 请求,再多一层流程:

  1. 请求进来。
  2. DispatcherServlet 接住请求。
  3. 找到对应的 Controller 方法。
  4. 做参数绑定。
  5. 调用 Service。
  6. 返回 JSON / 页面。

6. 底层原理或设计思想

第一阶段不深挖源码,但你要先知道为什么 Spring 这样设计:

  1. 企业项目对象多、依赖复杂,用手工管理成本太高,所以需要容器。
  2. 横切逻辑会污染业务代码,所以需要代理/AOP。
  3. 大量项目结构类似,所以需要约定优于配置。
  4. 业务变化大,所以框架要提供扩展点,而不是写死流程。

这背后的设计思想是:

  1. 分离"对象使用"和"对象创建"。
  2. 分离"业务逻辑"和"通用能力"。
  3. 用配置和注解描述意图,用框架执行机制。

7. 一个最小可运行示例

下面这个例子只有一个目的:让你直观看到"对象不是我手动 new 的,而是 Spring 自动装起来的"。

java 复制代码
package com.example.demo;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Service;

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

    private final OrderService orderService;

    public DemoApplication(OrderService orderService) {
        this.orderService = orderService;
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) {
        orderService.createOrder();
    }
}

@Service
class InventoryService {
    public void reserve() {
        System.out.println("库存已锁定");
    }
}

@Service
class OrderService {

    private final InventoryService inventoryService;

    public OrderService(InventoryService inventoryService) {
        this.inventoryService = inventoryService;
    }

    public void createOrder() {
        inventoryService.reserve();
        System.out.println("订单已创建");
    }
}

你会看到输出:

text 复制代码
库存已锁定
订单已创建

关键观察点:

  1. 你没有手动 new OrderService()
  2. 你也没有手动 new InventoryService()
  3. Spring 容器自动创建并组装了它们。

8. 一个真实工程场景

假设你在做一个电商系统,OrderService 依赖:

  1. InventoryService:扣库存。
  2. CouponService:校验优惠券。
  3. PaymentService:生成支付单。
  4. OrderRepository:落库。

如果全都手动 new

  1. 依赖关系会扩散到很多地方。
  2. 替换实现会很痛。
  3. 测试时难以 Mock。

用 Spring 后:

  1. 这些服务都交给容器。
  2. OrderService 只声明依赖。
  3. 切换实现只改配置或注解。
  4. 测试时可以替换 Bean。

这就是为什么企业里几乎都用 Spring。

9. 常见误区

  1. 误区:Spring 就是 Spring Boot。
    纠正:Boot 是 Spring 的工程化入口,不是全部。
  2. 误区:@Autowired 很神秘。
    纠正:本质是容器在创建对象时做依赖注入。
  3. 误区:学 Spring 就是记注解。
    纠正:核心是容器、代理、请求流转机制。
  4. 误区:先看源码最有效。
    纠正:没有使用场景和主干认知时,看源码效率很低。

10. 高频面试题

  1. Spring 是什么?它解决了什么问题?
  2. IoC 和 DI 是什么关系?
  3. Spring 和 Spring Boot 有什么区别?
  4. Spring MVC 是 Spring 的一部分吗?
  5. 为什么企业项目普遍使用 Spring?

参考答题模板

答"Spring 是什么"时,尽量按这个顺序:

  1. 定义:Spring 是 Java 企业级开发框架体系。
  2. 问题:解决对象管理、依赖耦合、事务、Web 开发等问题。
  3. 机制:核心靠 IoC、AOP、MVC、事务管理。
  4. 场景:企业中常用 Spring Boot + MVC + 数据访问构建服务。

11. 自测题

  1. 为什么说 Spring 不是一个单点框架,而是一套体系?
  2. 如果没有 Spring,手动管理对象会出现什么问题?
  3. IoC 和 DI 用你自己的话解释一遍。
  4. Spring、Spring MVC、Spring Boot 各自负责什么?
  5. 你能不能用"电商订单服务"的例子解释为什么需要 Spring?

12. 学完这一节后我应该能做到什么

学完第一阶段,你至少应该能做到:

  1. 用 3 分钟讲清楚 Spring 是干什么的。
  2. 说清 Spring 解决了哪些开发问题。
  3. 分清 Spring / Spring MVC / Spring Boot 的关系。
  4. 看懂一个最基础的 Spring Boot 示例,知道容器接管了对象。

第一阶段练习题

  1. 用你自己的话写一段 150 字说明:为什么 Spring 在企业开发中这么常见。
  2. 画出下面关系图:Controller -> Service -> Repository,说明为什么这些对象适合交给容器管理。
  3. 回答这个问题:如果不用 Spring,OrderService 依赖 5 个服务时,你预计会出现哪些维护问题?
  4. 自己新建一个最小 Spring Boot 项目,把上面的 OrderService 跑起来。

第二阶段:核心概念

1. 学什么

这一阶段学 Spring 的根:

  1. Bean 是什么。
  2. 容器是什么,BeanFactoryApplicationContext 是什么关系。
  3. 依赖注入怎么发生。
  4. Bean 怎么注册。
  5. 常见作用域、注入方式和配置方式。

2. 为什么重要

Spring 大部分能力都建立在"Bean 被容器接管"这件事上。

如果这一阶段没吃透,后面你会出现这些问题:

  1. 看不懂为什么某个类能被注入,另一个不行。
  2. 不知道 Bean 冲突时为什么会报错。
  3. 事务、AOP 明明写了注解却不生效,不知道从哪查。

3. 它解决什么实际问题

核心概念阶段解决的是"对象如何组织起来"的问题。

没有容器时:

  1. 依赖关系分散在代码各处。
  2. 第三方组件很难纳入统一管理。
  3. 生命周期无法统一控制。
  4. 测试替换困难。

有了容器后:

  1. 对象创建统一入口。
  2. 依赖注入统一规则。
  3. 初始化和销毁有统一钩子。
  4. 切换实现和替换测试桩更容易。

4. 核心概念定义

Bean

Bean 就是交给 Spring 容器管理的对象。

不是所有 Java 对象都是 Bean,只有被 Spring 注册到容器里的对象才是 Bean。

容器

容器是 Spring 管理 Bean 的运行时环境,常用接口是 ApplicationContext

BeanDefinition

BeanDefinition 可以理解为"Bean 的说明书",里面描述了:

  1. 这个 Bean 对应哪个类。
  2. 作用域是什么。
  3. 初始化方法是什么。
  4. 依赖是什么。

依赖注入

依赖注入就是容器在创建对象时,把它需要的其他对象传进去。

作用域

Scope 含义 常见场景
singleton 容器内单例 默认,大多数 Service
prototype 每次获取新对象 少数状态对象
request 每次 HTTP 请求一个 Web 场景
session 每个会话一个 很少直接用

BeanFactory vs ApplicationContext

对比项 BeanFactory ApplicationContext
定位 基础容器 更完整的高级容器
功能 基本 Bean 获取 国际化、事件、AOP、环境、自动注册等
使用频率 理解原理时常见 工程里几乎总是用它

@Component vs @Bean

注解 用在哪 典型场景
@Component 标在类上 自己写的组件
@Service / @Repository / @Controller @Component 的语义化变种 分层标识
@Bean 标在方法上 第三方类、需要手工定制的 Bean

注入方式对比

方式 推荐度 原因
构造器注入 最推荐 依赖明确、利于测试、便于不可变设计
Setter 注入 可用 适合可选依赖
字段注入 不推荐 不利于测试,依赖不显式

5. 工作流程或运行机制

从"类"到"能用的 Bean",大致是这个过程:

  1. Spring 扫描配置类或组件类。
  2. 解析出 BeanDefinition。
  3. 容器创建 Bean 实例。
  4. 解析并注入依赖。
  5. 调用初始化回调。
  6. 把 Bean 放入单例池。
  7. 业务代码使用它。

可以把它理解成:

类只是候选人,BeanDefinition 是档案,真正进容器并完成装配后,才变成可工作的 Bean。

6. 底层原理或设计思想

Spring 没有发明"对象"本身,它做的是"对象图管理"。

设计思想有三个关键点:

  1. 元数据驱动:通过注解、配置类、@Bean 方法告诉容器该怎么装配。
  2. 延迟复杂性:业务代码不需要知道对象怎么创建。
  3. 统一生命周期:创建、注入、初始化、销毁都有固定阶段。

这也是为什么 Spring 能把事务、AOP、事件、配置都统一挂到容器上。

7. 一个最小可运行示例

下面这个例子同时演示:

  1. 多个实现类。
  2. @Qualifier 指定注入。
  3. @Bean 注册第三方对象。
java 复制代码
package com.example.demo;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

    private final CheckoutService checkoutService;

    public DemoApplication(CheckoutService checkoutService) {
        this.checkoutService = checkoutService;
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) {
        System.out.println(checkoutService.checkout());
    }
}

interface PayService {
    String pay();
}

@Component("alipayService")
class AlipayService implements PayService {
    @Override
    public String pay() {
        return "使用支付宝支付";
    }
}

@Component("wechatPayService")
class WechatPayService implements PayService {
    @Override
    public String pay() {
        return "使用微信支付";
    }
}

@Service
class CheckoutService {

    private final PayService payService;
    private final IdGenerator idGenerator;

    public CheckoutService(
            @Qualifier("alipayService") PayService payService,
            IdGenerator idGenerator) {
        this.payService = payService;
        this.idGenerator = idGenerator;
    }

    public String checkout() {
        return idGenerator.nextId() + " -> " + payService.pay();
    }
}

class IdGenerator {
    public String nextId() {
        return "ORDER-" + System.currentTimeMillis();
    }
}

@Configuration
class AppConfig {
    @Bean
    public IdGenerator idGenerator() {
        return new IdGenerator();
    }
}

8. 一个真实工程场景

支付网关通常有多种实现:

  1. 支付宝
  2. 微信支付
  3. 银联
  4. 测试环境模拟支付

如果不使用容器和接口抽象,切换实现会改动很多业务代码。

合理做法:

  1. 定义 PayService 接口。
  2. 各个支付方式各自实现。
  3. 用 Spring 管理这些实现。
  4. 通过 @Qualifier@Primary、配置项等方式选择具体实现。

9. 常见误区

  1. 误区:Bean 就是 Java 类。
    纠正:Bean 是"被容器管理的对象",类只是定义。
  2. 误区:单例 Bean 一定线程安全。
    纠正:单例只代表实例数量,不代表内部状态安全。
  3. 误区:字段注入最省事,所以最好。
    纠正:构造器注入更清晰、更利于测试。
  4. 误区:@Component@Bean 完全一样。
    纠正:本质都是注册 Bean,但使用场景不同。

10. 高频面试题

  1. 什么是 Bean?
  2. BeanFactory 和 ApplicationContext 有什么区别?
  3. Spring 中常见的 Bean 注入方式有哪些?推荐哪种?
  4. @Component@Bean 的区别是什么?
  5. 单例 Bean 是线程安全的吗?

11. 自测题

  1. 为什么说"Bean != 普通对象"?
  2. 你如何向别人解释 @Bean 的使用场景?
  3. 为什么构造器注入比字段注入更推荐?
  4. 如果容器里有两个 PayService,Spring 怎么知道注入哪个?
  5. singletonprototype 在工程上的差异是什么?

12. 学完这一节后我应该能做到什么

  1. 解释 Bean、容器、依赖注入的含义。
  2. 能用 @Component@Bean@Qualifier 完成基本装配。
  3. 理解为什么推荐构造器注入。
  4. 知道 Bean 作用域的基本差异。

第三阶段:核心机制

1. 学什么

这一阶段学习 Spring 最容易在项目和面试中出现的问题源头:

  1. Bean 生命周期。
  2. AOP 机制。
  3. 动态代理。
  4. 事务机制。
  5. Spring MVC 请求处理机制。

2. 为什么重要

这一阶段决定你是否只是"会写注解",还是"真正理解框架行为"。

很多高频故障都来自这里:

  1. 事务失效。
  2. AOP 不生效。
  3. Controller 能调,事务却没开。
  4. 明明加了组件注解,启动后行为不符合预期。

3. 它解决什么实际问题

AOP 解决什么

把日志、事务、权限、监控这类"很多地方都要做"的逻辑,从业务代码中剥离出来。

事务解决什么

保证一组数据库操作要么全成功,要么全失败。

MVC 解决什么

把 HTTP 请求转成统一的 Controller 调用模型,不再直接手写 Servlet 样板代码。

4. 核心概念定义

概念 定义
Bean 生命周期 Bean 从创建、注入、初始化到销毁的完整过程
AOP 面向切面编程,把横切逻辑统一织入目标方法
代理 用代理对象包一层,在调用前后增加附加行为
Join Point 可被切入的执行点,Spring AOP 里主要是方法执行
Pointcut 切点,定义拦截哪些方法
Advice 通知,定义拦截后做什么
@Transactional 用声明式事务管理方法执行边界
DispatcherServlet Spring MVC 的前端控制器

JDK 动态代理 vs CGLIB

对比项 JDK 动态代理 CGLIB
代理对象要求 目标类要有接口 不要求接口
原理 代理接口 生成子类
常见场景 面向接口编程 无接口类代理

5. 工作流程或运行机制

Bean 生命周期简化版

  1. 实例化 Bean。
  2. 注入依赖。
  3. 执行 Aware 回调。
  4. 执行 BeanPostProcessor 前置逻辑。
  5. 执行初始化方法。
  6. 执行 BeanPostProcessor 后置逻辑。
  7. Bean 可用。
  8. 容器关闭时执行销毁逻辑。

事务执行流程

  1. 调用代理对象的方法。
  2. 事务拦截器判断是否需要开启事务。
  3. 开启事务。
  4. 调用目标方法。
  5. 正常则提交,异常则回滚。

MVC 请求流程

Service Controller HandlerAdapter HandlerMapping DispatcherServlet Client Service Controller HandlerAdapter HandlerMapping DispatcherServlet Client HTTP Request 查找处理器 返回 Handler 适配调用 调用 Controller 方法 执行业务 返回结果 对象 / 视图 JSON / 页面

6. 底层原理或设计思想

为什么事务和日志能"自动生效"

因为你调用的通常不是目标对象本体,而是 Spring 给你包出来的代理对象。

代理做的事:

  1. 在调用前加逻辑。
  2. 调目标方法。
  3. 在调用后处理提交、回滚、日志、埋点等。

为什么 AOP 用代理

因为这样不用改业务类源码,就能在方法调用前后附加行为,符合开闭原则。

为什么 MVC 用 DispatcherServlet

因为它能把所有请求先统一接住,再按规则转发给不同 Controller,这样 Web 层行为可统一扩展。

7. 一个最小可运行示例

下面这个例子演示:

  1. @Aspect 做日志。
  2. @Transactional 做事务边界。
java 复制代码
package com.example.demo;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;

@SpringBootApplication
@EnableTransactionManagement
public class DemoApplication implements CommandLineRunner {

    private final OrderService orderService;

    public DemoApplication(OrderService orderService) {
        this.orderService = orderService;
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) {
        orderService.submitOrder();
    }
}

@Service
class OrderService {

    @Transactional
    public void submitOrder() {
        System.out.println("创建订单");
        System.out.println("扣减库存");
    }
}

@Aspect
@Component
class LogAspect {

    @Around("execution(* com.example.demo.OrderService.*(..))")
    public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("方法开始: " + joinPoint.getSignature().getName());
        Object result = joinPoint.proceed();
        System.out.println("方法结束: " + joinPoint.getSignature().getName());
        return result;
    }
}

8. 一个真实工程场景

下单流程通常包含:

  1. 创建订单记录。
  2. 扣减库存。
  3. 锁定优惠券。
  4. 记录操作日志。

这里最合适的设计是:

  1. @Transactional 包裹 Service 方法,保证一致性。
  2. 用 AOP 记录操作日志或接口耗时。
  3. Controller 只负责入参和返回,不直接写事务逻辑。

9. 常见误区

  1. 误区:AOP 是在源码层面改代码。
    纠正:Spring AOP 默认是运行期代理,不是直接改源码。
  2. 误区:@Transactional 标了就一定生效。
    纠正:自调用、非 public 方法、异常被吞掉等都可能导致失效。
  3. 误区:Controller 上加事务也很好。
    纠正:事务边界更适合放在 Service 层。
  4. 误区:AOP 能拦截所有东西。
    纠正:Spring AOP 主要基于方法执行点。

10. 高频面试题

  1. Spring AOP 是怎么实现的?
  2. JDK 动态代理和 CGLIB 有什么区别?
  3. @Transactional 的底层原理是什么?
  4. Spring 事务为什么会失效?
  5. 一次 Spring MVC 请求从进入到返回经历了什么?

11. 自测题

  1. 为什么说事务本质上依赖代理?
  2. 为什么同类内部方法互调可能导致事务失效?
  3. DispatcherServlet 在 MVC 中起什么作用?
  4. AOP 解决的到底是什么类型的问题?
  5. 你能按步骤说出一个方法被事务代理包裹后的执行过程吗?

12. 学完这一节后我应该能做到什么

  1. 解释 Spring AOP 的基本实现思路。
  2. 解释 @Transactional 为什么有效、为什么有时失效。
  3. 能说清 MVC 请求的主流程。
  4. 能用"代理"解释事务、日志、权限等横切能力。

第四阶段:底层原理

1. 学什么

这一阶段把前面"会用"和"会解释"连接起来,重点理解:

  1. Spring 容器启动时干了什么。
  2. refresh() 大致在做什么。
  3. BeanDefinition 怎么来的。
  4. BeanPostProcessorBeanFactoryPostProcessor 做什么。
  5. 自动代理创建的大致流程。

2. 为什么重要

这是从"会用 Spring"跨到"能做中级解释和排错"的关键阶段。

你不需要一上来把全部源码背下来,但至少要知道主链路。

3. 它解决什么实际问题

底层原理阶段不是为了炫技,而是为了解决下面几类真实问题:

  1. 启动失败时,你知道卡在哪一层。
  2. Bean 为什么没注册进去,你知道去看扫描、条件装配、配置类解析。
  3. 事务代理为什么没生效,你知道它和代理创建链有关。
  4. 想自定义扩展时,你知道该挂在哪个扩展点。

4. 核心概念定义

概念 作用
refresh() 容器启动核心流程
BeanDefinition Bean 的描述信息
BeanFactoryPostProcessor 在 Bean 实例化前,修改 Bean 定义
BeanPostProcessor 在 Bean 实例化后、初始化前后做处理
InstantiationAwareBeanPostProcessor 更早阶段介入实例化流程
Auto Proxy Creator 为符合条件的 Bean 创建代理

5. 工作流程或运行机制

Spring 容器启动主流程(简化)

  1. 创建 ApplicationContext
  2. 加载配置类、扫描组件。
  3. 注册 BeanDefinition。
  4. 执行 BeanFactoryPostProcessor
  5. 注册 BeanPostProcessor
  6. 实例化非懒加载单例 Bean。
  7. 完成容器刷新。

Bean 被代理的大致流程

  1. Spring 先按正常流程创建 Bean。
  2. 某个后置处理器判断这个 Bean 是否需要代理。
  3. 如果需要,就生成代理对象替代原对象放入容器。
  4. 后续你拿到的其实是代理对象。

6. 底层原理或设计思想

Spring 的底层设计非常强调"分阶段"和"可插拔":

  1. 先注册定义,再创建对象。
  2. 先给扩展点机会,再正式实例化。
  3. 通过后置处理器,在不入侵业务代码的前提下增强行为。

这就是为什么 Spring 能不断叠加功能,但业务代码改动很少。

一个很重要的理解

Spring 核心不是"注解驱动",而是"元数据 + 生命周期阶段 + 扩展点"驱动。

注解只是告诉 Spring "我要什么",真正工作的仍然是容器生命周期和各种处理器。

7. 一个最小可运行示例

下面用 BeanPostProcessor 看看 Bean 初始化前后发生了什么:

java 复制代码
package com.example.demo;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Bean
    public UserService userService() {
        return new UserService();
    }
}

class UserService {
    public UserService() {
        System.out.println("构造 UserService");
    }
}

@Component
class TraceBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if ("userService".equals(beanName)) {
            System.out.println("初始化前: " + beanName);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if ("userService".equals(beanName)) {
            System.out.println("初始化后: " + beanName);
        }
        return bean;
    }
}

你会看到类似输出:

text 复制代码
构造 UserService
初始化前: userService
初始化后: userService

这能帮你直观看到:Spring 对 Bean 的处理不是"一步到位",而是分阶段进行的。

8. 一个真实工程场景

比如你希望所有带某个注解的 Service 在启动时自动注册审计信息,或者统一包一层代理记录调用耗时。

这时通常不是去改每个类,而是:

  1. 写一个后置处理器。
  2. 在 Bean 初始化阶段统一扫描。
  3. 对符合条件的 Bean 做增强。

这就是 Spring 扩展点的工程价值。

9. 常见误区

  1. 误区:Spring 一启动就把所有类都变成 Bean。
    纠正:只有被扫描、被配置、符合条件的类才会注册。
  2. 误区:注解是 JVM 自动帮你注入对象。
    纠正:注解只是元数据,真正执行装配的是 Spring。
  3. 误区:代理对象和原对象完全没差别。
    纠正:很多行为差异都来自你拿到的是代理。

10. 高频面试题

  1. Spring 容器启动大致流程是什么?
  2. 什么是 BeanDefinition?
  3. BeanFactoryPostProcessor 和 BeanPostProcessor 的区别是什么?
  4. Spring 是在哪个阶段创建代理的?
  5. 为什么说注解只是元数据?

11. 自测题

  1. refresh() 这个词在 Spring 里大概意味着什么?
  2. 为什么 Spring 要区分"Bean 定义"和"Bean 实例"?
  3. 如果要在 Bean 创建前修改其配置,你应该想到哪个扩展点?
  4. 代理对象通常是在什么阶段替换掉原始 Bean 的?

12. 学完这一节后我应该能做到什么

  1. 能从"容器启动 -> 注册定义 -> 实例化 -> 后处理 -> 代理"这个链路解释 Spring。
  2. 知道常见后置处理器的职责边界。
  3. 遇到容器启动问题时,知道去怀疑扫描、定义注册、条件装配和代理链。

第五阶段:工程实践

1. 学什么

这一阶段我们不再停留在知识点,而是看企业里通常怎么用 Spring:

  1. Spring Boot 项目结构。
  2. Controller / Service / Repository 分层。
  3. 配置文件、Profile、配置绑定。
  4. 参数校验、统一异常处理、日志。
  5. 事务边界、接口设计、DTO/VO。
  6. 测试基础。

2. 为什么重要

面试和真实开发都不看你会不会"单点注解",而看你能不能把一个服务写得像工程。

工程实践是把 Spring 从"概念"变成"产能"的阶段。

3. 它解决什么实际问题

工程实践阶段解决的问题包括:

  1. 项目结构混乱。
  2. 配置散落、环境切换困难。
  3. Controller 逻辑太重。
  4. 参数校验和异常处理不统一。
  5. 日志不可追踪,问题难排查。

4. 核心概念定义

概念 含义
Starter 帮你收敛依赖和自动配置的一组依赖包
Auto Configuration 根据条件自动装配组件
Profile 多环境配置切换机制
@ConfigurationProperties 把配置绑定到对象
DTO 面向接口传输的数据对象
VO 面向展示或返回的数据对象
@Valid / @Validated 参数校验
@RestControllerAdvice 全局异常处理

企业常见项目结构

text 复制代码
src/main/java
├── controller
├── service
├── service/impl
├── repository 或 mapper
├── domain 或 entity
├── dto
├── vo
├── config
├── common
└── Application.java

5. 工作流程或运行机制

一个标准的接口请求大致这样流转:

  1. 请求进入 Controller。
  2. @RequestBody 绑定参数。
  3. @Valid 执行参数校验。
  4. Controller 调用 Service。
  5. Service 开启事务、处理业务、访问数据库。
  6. 返回 VO 或统一响应对象。
  7. 发生异常时由全局异常处理器统一接住。

6. 底层原理或设计思想

工程实践阶段最重要的思想有四个:

  1. 分层不是为了好看,而是为了职责单一、便于测试和扩展。
  2. 配置外置化不是为了"高级",而是为了环境切换和运维协作。
  3. DTO / VO 分离不是为了形式主义,而是为了隔离内部模型和外部协议。
  4. 异常统一处理不是为了省代码,而是为了稳定输出和统一观测。

过滤器、拦截器、AOP 对比

能力 作用层 常见用途
Filter Servlet 层 编码、跨域、链路追踪入口
Interceptor MVC 层 登录态、权限、请求日志
AOP 方法调用层 事务、埋点、审计、统一增强

7. 一个最小可运行示例

下面是一个更贴近真实项目的 REST 接口最小骨架:

java 复制代码
package com.example.demo;

import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestController
@RequestMapping("/orders")
class OrderController {

    private final OrderService orderService;

    OrderController(OrderService orderService) {
        this.orderService = orderService;
    }

    @PostMapping
    public OrderVO create(@Valid @RequestBody CreateOrderRequest request) {
        return orderService.create(request);
    }
}

record CreateOrderRequest(
        @NotBlank(message = "商品编码不能为空") String productCode,
        @Min(value = 1, message = "购买数量必须大于 0") int count) {
}

record OrderVO(String orderNo, String status) {
}

@org.springframework.stereotype.Service
class OrderService {
    public OrderVO create(CreateOrderRequest request) {
        return new OrderVO("ORDER-1001", "CREATED");
    }
}

@RestControllerAdvice
class GlobalExceptionHandler {

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public String handle(MethodArgumentNotValidException ex) {
        return ex.getBindingResult().getFieldError().getDefaultMessage();
    }
}

对应配置文件:

yaml 复制代码
spring:
  application:
    name: spring-learning-demo

server:
  port: 8080

8. 一个真实工程场景

典型的订单服务一般至少要做到:

  1. 下单接口参数校验。
  2. Service 层事务控制。
  3. 异常统一转换。
  4. 多环境配置切换。
  5. 日志中带请求标识。
  6. 和数据库、Redis、MQ 等组件整合。

企业里通常不是"裸 Spring",而是:

  1. Spring Boot 负责启动和装配。
  2. Spring MVC 负责接口层。
  3. Spring Transaction 负责事务。
  4. Spring + MyBatis/JPA 负责数据层。

9. 常见误区

  1. 误区:Controller 可以写全部业务逻辑。
    纠正:Controller 负责输入输出,不应承载核心业务。
  2. 误区:数据库实体直接当接口返回对象。
    纠正:最好通过 DTO / VO 隔离内部实现。
  3. 误区:所有配置都写在一个 application.yml
    纠正:应结合 Profile 做多环境拆分。
  4. 误区:所有异常都在 Controller 里 try-catch。
    纠正:优先使用全局异常处理。

10. 高频面试题

  1. Spring Boot 为什么能做到开箱即用?
  2. @ConfigurationProperties@Value 有什么区别?
  3. 为什么要做统一异常处理?
  4. 为什么事务一般放在 Service 层?
  5. Filter、Interceptor、AOP 有什么区别?

11. 自测题

  1. 为什么企业项目常见分层结构?
  2. DTO 和 Entity 混用会带来什么问题?
  3. 你会把参数校验放在哪一层?为什么?
  4. 多环境配置如何组织更合理?
  5. 为什么统一异常处理比到处 try-catch 更好?

12. 学完这一节后我应该能做到什么

  1. 能搭一个结构合理的 Spring Boot 服务。
  2. 能写 Controller、Service、异常处理、配置文件。
  3. 知道企业项目里 Spring 各模块如何组合使用。
  4. 能说出分层、校验、事务、日志、配置管理的工程价值。

第六阶段:常见问题与排错

1. 学什么

这一阶段学习的是实战里最值钱的一项能力:排错。

重点包括:

  1. Bean 注入失败。
  2. Bean 冲突。
  3. 事务失效。
  4. 请求 404 / 405 / 415 / 400。
  5. 配置不生效。
  6. 启动慢或启动失败。

2. 为什么重要

很多开发者不是不会写代码,而是不会定位问题。

Spring 体系一旦规模起来,问题往往不是语法错误,而是配置、装配、代理、链路上的错位。

3. 它解决什么实际问题

这一阶段解决的不是"概念记忆",而是这些具体场景:

  1. NoSuchBeanDefinitionException
  2. NoUniqueBeanDefinitionException
  3. BeanCurrentlyInCreationException
  4. @Transactional 不回滚
  5. 接口明明写了却 404
  6. 参数提交了却报 415 / 400
  7. 配置改了却像没生效

4. 核心概念定义

错误/概念 含义
NoSuchBeanDefinitionException 找不到要注入的 Bean
NoUniqueBeanDefinitionException 找到多个同类型 Bean,不知道选哪个
循环依赖 A 依赖 B,B 又依赖 A
事务失效 标了事务但没开启、没回滚或没传播
415 请求体类型或 Content-Type 不匹配
400 请求参数绑定失败

5. 工作流程或运行机制

推荐排错顺序:

  1. 先看完整异常栈。
  2. 找最根因的异常,而不是只看最外层报错。
  3. 判断问题落在哪一层:容器、MVC、事务、配置、数据访问。
  4. 复现最小场景。
  5. 验证假设,而不是盲改配置。

一张高频排错表

症状 常见根因 先查什么 怎么改
注入失败 没扫描到、没注册 Bean 包路径、注解、配置类 调整扫描路径或注册方式
注入冲突 同类型多个 Bean 是否有 @Primary / @Qualifier 指定注入目标
事务不回滚 自调用、异常被吞、异常类型不对 调用路径、异常处理 从代理入口调用,明确回滚规则
404 映射没注册、路径写错 启动日志、@RequestMapping 修正映射
415 Content-Type 不对 请求头和入参注解 发送 JSON 并加 application/json
配置不生效 Profile 错、前缀错、未绑定 激活环境、配置键名 校正配置与绑定类

6. 底层原理或设计思想

真正高效的排错,不是"经验玄学",而是把问题映射回机制:

  1. Bean 问题,本质是容器装配问题。
  2. 事务问题,本质是代理和调用路径问题。
  3. MVC 问题,本质是请求映射和参数绑定问题。
  4. 配置问题,本质是环境加载和绑定规则问题。

所以排错时一定要问:

  1. 这个问题发生在哪层?
  2. 这一层的核心机制是什么?
  3. 哪个前提没满足?

7. 一个最小可运行示例

下面是一个最常见的"注入失败"示例:

java 复制代码
package com.demo.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Service;

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

// 假设这个类放到了 com.other.service 包下,并且没有被扫描到
@Service
class UserService {
}

如果 UserService 不在启动类所在包及其子包下,又没显式 @ComponentScan,就可能注入失败。

修复方式之一:

java 复制代码
@SpringBootApplication(scanBasePackages = {"com.demo.app", "com.other.service"})
public class DemoApplication {
}

8. 一个真实工程场景

真实项目里最常见的事务问题之一:

OrderService.createOrder() 里调用同类的 saveAudit(),而 saveAudit() 上标了 @Transactional,结果事务没生效。

原因:

  1. 同类内部调用没有经过 Spring 代理。
  2. 事务增强是挂在代理对象上的。

正确做法通常有三种:

  1. 把事务方法拆到另一个 Bean 中。
  2. 通过代理对象调用。
  3. 重新设计事务边界。

9. 常见误区

  1. 误区:只要报错就先怀疑版本冲突。
    纠正:先看具体异常链和问题层级。
  2. 误区:事务不生效就把注解到处加。
    纠正:先看调用是否经过代理。
  3. 误区:出现循环依赖就直接 @Lazy
    纠正:先判断是不是设计有问题。
  4. 误区:参数绑定失败就改 Controller 签名碰运气。
    纠正:先确认请求格式、注解和字段名是否一致。

10. 高频面试题

  1. Spring 中 Bean 注入失败通常怎么排查?
  2. 为什么 @Transactional 会失效?
  3. 你如何排查一个接口 404?
  4. NoSuchBeanDefinitionExceptionNoUniqueBeanDefinitionException 有什么区别?
  5. 你如何定位配置不生效的问题?

11. 自测题

  1. 如果启动时报找不到 Bean,你第一步看什么?
  2. 如果事务没有回滚,你会依次检查哪几项?
  3. 415 和 400 在 Spring MVC 中通常分别意味着什么?
  4. 如果某个配置项你确认写了,但程序没读到,可能的原因有哪些?

12. 学完这一节后我应该能做到什么

  1. 能按机制分层定位 Spring 问题。
  2. 能独立处理大部分常见装配、事务、MVC、配置类错误。
  3. 不再靠"试错式改注解",而是有步骤地排查。

第七阶段:面试与评估

1. 学什么

这一阶段学的不是新知识,而是把前面的知识变成"能说出来、说得清楚、说得像做过项目"。

重点包括:

  1. 面试高频题的答法结构。
  2. 如何把原理题和项目经历连起来。
  3. 如何避免只背八股。

2. 为什么重要

面试官要的不是"你背过名词",而是:

  1. 你是否真的理解。
  2. 你是否在项目里用过。
  3. 你是否知道常见问题与权衡。

3. 它解决什么实际问题

面试中经常出现这些困境:

  1. 懂一点,但说不成体系。
  2. 会用,却解释不出原理。
  3. 会背概念,但一问项目场景就断。

这一阶段就是把知识组织成可表达、可评估的形式。

4. 核心概念定义

面试回答建议遵循一个固定模板:

  1. 定义:它是什么。
  2. 目标:它解决什么问题。
  3. 机制:它怎么实现。
  4. 场景:项目里怎么用。
  5. 坑点:什么时候会失效或踩坑。

这个模板适用于回答:

  1. IoC
  2. AOP
  3. 事务
  4. MVC
  5. Spring Boot 自动配置

5. 工作流程或运行机制

一道原理题怎么答

以"Spring 事务是怎么实现的"为例:

  1. 先说定义:Spring 常用声明式事务管理。
  2. 再说问题:避免手写事务模板代码。
  3. 再说机制:基于 AOP/代理,在方法前后开启、提交、回滚事务。
  4. 再说前提:必须经过代理调用。
  5. 再说坑:自调用、异常被吞、方法可见性问题。
  6. 再说场景:订单、库存、优惠券这类一致性操作。

6. 底层原理或设计思想

好的面试回答有两个设计原则:

  1. 不只讲"是什么",还讲"为什么这样设计"。
  2. 不只讲"理论",还讲"实际项目怎么用、哪里会出问题"。

面试官最喜欢追问的不是定义本身,而是:

  1. 为什么要这样设计?
  2. 这样设计的代价是什么?
  3. 你在项目里怎么用?
  4. 你踩过什么坑?

7. 一个最小可运行示例

下面这段代码适合你拿来练"事务 + AOP + 分层"的面试表达:

java 复制代码
@RestController
class OrderController {

    private final OrderService orderService;

    OrderController(OrderService orderService) {
        this.orderService = orderService;
    }

    @PostMapping("/orders")
    public String create() {
        orderService.createOrder();
        return "ok";
    }
}

@Service
class OrderService {

    @Transactional
    public void createOrder() {
        // 写订单
        // 扣库存
    }
}

你可以围绕它回答:

  1. Spring 如何把 Controller 注入到容器。
  2. 事务为什么要放 Service。
  3. @Transactional 为什么依赖代理。
  4. 一次请求如何从 Controller 走到 Service。

8. 一个真实工程场景

如果面试官问你:"你们项目里 Spring 怎么用的?"

一个像样的回答可以是:

  1. 用 Spring Boot 搭建服务。
  2. 用 Spring MVC 对外提供 REST 接口。
  3. 用 Spring 的事务管理保证下单、库存扣减的一致性。
  4. @ConfigurationProperties 管理多环境配置。
  5. 用全局异常处理、参数校验和日志链路保证接口稳定性。
  6. 遇到事务失效和 Bean 冲突时,能从代理和容器装配角度排查。

9. 常见误区

  1. 误区:只背标准答案。
    纠正:必须把答案挂到项目场景上。
  2. 误区:原理题回答越细越好。
    纠正:先答主干,再根据追问展开。
  3. 误区:只讲优点,不讲坑。
    纠正:中级面试更看重边界和问题意识。

10. 高频面试题

  1. Spring 的核心思想是什么?
  2. IoC 和 DI 有什么区别与联系?
  3. Bean 生命周期有哪些阶段?
  4. Spring AOP 和代理是什么关系?
  5. Spring 事务底层如何实现?
  6. Spring Boot 自动配置原理是什么?
  7. Spring MVC 的请求流程是什么?
  8. 为什么事务通常写在 Service 而不是 Controller?

11. 自测题

  1. 你能否用"定义 + 问题 + 机制 + 场景 + 坑"回答 IoC?
  2. 你能否在 2 分钟内讲清事务底层原理?
  3. 如果面试官追问"为什么自调用会导致事务失效",你能解释代理链吗?
  4. 如果面试官让你说一个项目中的 Spring 排错案例,你能讲出来吗?

12. 学完这一节后我应该能做到什么

  1. 用结构化方式回答 Spring 核心问题。
  2. 把 Spring 原理和项目经验连起来。
  3. 对基础到中级面试有较强应对能力。

第八阶段:学习总结与知识闭环

1. 学什么

最后一阶段做三件事:

  1. 把 Spring 知识串成一张网。
  2. 明确哪些内容已经够用,哪些值得继续深入。
  3. 制定下一步进阶路线。

2. 为什么重要

很多人学完一堆知识点,却没有闭环:

  1. 不知道什么是重点。
  2. 不知道该怎么继续练。
  3. 不知道怎么把知识迁移到项目。

3. 它解决什么实际问题

这一阶段解决的是"学完就散"的问题。

闭环的目标是:

  1. 概念能解释。
  2. 代码能写。
  3. 故障能查。
  4. 面试能答。
  5. 项目能落。

4. 核心概念定义

学习闭环

学习闭环 = 概念 -> 原理 -> 示例 -> 实战 -> 排错 -> 复盘 -> 再表达。

学习本质

Spring 真正要建立的是下面这条主线:

  1. 容器管理对象。
  2. 代理增强行为。
  3. MVC 组织请求。
  4. Boot 收敛工程。
  5. 工程规范让项目可维护。

5. 工作流程或运行机制

推荐你把知识复盘成下面这张图:
IoC / DI
Bean 生命周期
AOP / 代理
事务管理
Spring MVC
Spring Boot 工程化
工程实践与排错
面试表达与项目实战

6. 底层原理或设计思想

Spring 的学习不要停在"功能点"层面,而要逐步建立下面三种意识:

  1. 容器意识:先想对象是否该交给容器。
  2. 代理意识:先想增强逻辑是否应交给 AOP。
  3. 分层意识:先想职责边界是否合理。

真正的中级工程师,不是会背更多名词,而是做设计和排错时能自然调用这些意识。

7. 一个最小可运行示例

如果你想验证自己是否真的形成闭环,建议自己做一个最小项目:

  1. 提供一个 POST /orders 接口。
  2. 校验参数。
  3. 调用 Service 创建订单。
  4. 用事务包裹业务。
  5. 用全局异常处理返回错误。
  6. 用配置文件区分 dev / test。

只要这个项目你能独立从 0 写出来,并解释每一层为什么这样写,你就已经完成了非常关键的一轮闭环。

8. 一个真实工程场景

企业里通常不会单独问"你会不会 Spring",而是看你能不能在一个服务里合理使用它:

  1. 结构清楚。
  2. 接口规范。
  3. 事务边界正确。
  4. 异常处理统一。
  5. 配置可切环境。
  6. 问题能快速定位。

所以学 Spring 的最终目标,不是"学懂框架",而是"能用框架交付业务"。

9. 常见误区

  1. 误区:学完课程就算掌握了。
    纠正:必须经过编码、排错、讲解三轮验证。
  2. 误区:中级就是背更多源码。
    纠正:中级更重要的是能解释、能设计、能定位。
  3. 误区:Spring 学完就结束了。
    纠正:后面还有数据访问、缓存、消息、权限、微服务等扩展。

10. 高频面试题

  1. Spring 体系里你认为最核心的思想是什么?
  2. 你是如何理解"容器"和"代理"这两个关键抽象的?
  3. 如果让你从 0 搭一个 Spring Boot 服务,你会怎么组织结构?
  4. 你认为初学者最容易踩的 Spring 坑是什么?

11. 自测题

  1. 你能否画出 Spring 的知识主线图?
  2. 你能否用一句话解释 IoC、AOP、MVC、Boot 各自位置?
  3. 你能否设计一个小项目,覆盖 Bean、事务、MVC、配置、异常处理?

12. 学完这一节后我应该能做到什么

  1. 知道 Spring 的学习闭环是什么。
  2. 明确下一步进阶方向。
  3. 具备把 Spring 知识迁移到真实项目的能力。

学习评估体系

1. 入门达标标准

满足下面 5 条,算入门达标:

  1. 能说清 Spring、Spring MVC、Spring Boot 的关系。
  2. 能解释 IoC、DI、Bean、容器的基本含义。
  3. 能独立跑起一个最小 Spring Boot 项目。
  4. 能写出一个简单的 Controller + Service 示例。
  5. 知道事务、AOP、MVC 分别大致解决什么问题。

2. 初级达标标准

满足下面 6 条,算初级达标:

  1. 能用构造器注入完成多层依赖装配。
  2. 能解释 Bean 生命周期主流程。
  3. 能使用 @Transactional,并知道常见失效场景。
  4. 能完成参数校验、全局异常处理、配置绑定。
  5. 能排查常见 Bean 注入和 MVC 映射问题。
  6. 能结合项目说明 Spring 在工程中的使用方式。

3. 中级达标标准

满足下面 7 条,算中级达标:

  1. 能解释 Spring 容器启动主流程。
  2. 能解释 AOP 与代理的关系,以及事务如何基于代理生效。
  3. 能说出 BeanPostProcessorBeanFactoryPostProcessor 的职责差异。
  4. 能设计合理的事务边界、分层结构和配置组织方式。
  5. 能针对事务失效、Bean 冲突、配置不生效给出定位路径。
  6. 能把原理题和项目场景自然结合。
  7. 能独立完成一个中小型 Spring Boot 服务原型。

4. 一套自测题

基础题

  1. 什么是 IoC?它为什么能降低耦合?
  2. Bean 和普通对象的区别是什么?
  3. @Component@Bean 的差别是什么?
  4. Spring MVC 中 DispatcherServlet 的作用是什么?
  5. Spring Boot 为什么能简化开发?

进阶题

  1. Bean 生命周期有哪些关键阶段?
  2. Spring AOP 默认是如何实现的?
  3. @Transactional 为什么依赖代理?
  4. 同类内部方法调用为什么可能导致事务失效?
  5. BeanFactoryPostProcessorBeanPostProcessor 有什么区别?

排错题

  1. 出现 NoSuchBeanDefinitionException 时你如何排查?
  2. 一个接口返回 415,你会检查哪些地方?
  3. 配置项明明写了却没有生效,可能原因有哪些?

5. 一套面试题

  1. Spring 的核心思想是什么?
  2. IoC 和 DI 有什么区别与联系?
  3. Spring Bean 的生命周期是什么?
  4. Spring 如何解决横切逻辑问题?
  5. AOP 和动态代理是什么关系?
  6. Spring 中事务是如何实现的?
  7. Spring 事务什么时候会失效?
  8. Spring MVC 的请求流程是什么?
  9. Spring Boot 自动配置原理你怎么理解?
  10. 为什么项目里通常把事务写在 Service 层?
  11. @Autowired@Resource 的区别是什么?
  12. 如何排查一个 Bean 注入失败的问题?

6. 一套实战任务

任务 1:最小容器使用

  1. 新建一个 Spring Boot 项目。
  2. 编写 UserServiceOrderService
  3. 使用构造器注入。
  4. 启动项目并打印调用结果。

任务 2:参数校验与异常处理

  1. 编写 POST /users 接口。
  2. 使用 @Valid 做参数校验。
  3. 使用 @RestControllerAdvice 返回统一错误信息。

任务 3:事务与排错

  1. 写一个下单 Service。
  2. 在其中模拟两步数据库操作。
  3. 中间抛出异常,观察事务回滚。
  4. 再做一次"同类内部调用"实验,验证事务失效。

7. 一套项目任务

项目名称

订单中心 Demo

目标

实现一个最小但完整的 Spring Boot 服务,至少包括:

  1. 用户下单接口。
  2. 查询订单接口。
  3. 参数校验。
  4. 统一异常处理。
  5. 配置文件按环境拆分。
  6. Service 层事务。
  7. 基础日志打印。
  8. 至少一项常见错误的排查记录。

建议模块

  1. controller:订单接口。
  2. service:下单、查单逻辑。
  3. repositorymapper:数据访问。
  4. dto / vo:入参与返回对象。
  5. config:配置绑定、MVC 配置。
  6. common:统一返回、异常体系。

进阶要求

  1. 增加一个支付实现接口,演示多实现 Bean 注入。
  2. 增加一个 AOP 日志切面。
  3. 演示一个事务失效案例,并写出原因分析。

8. 对你回答的评分标准

总分 100 分,建议这样评估:

维度 分值 评分标准
概念理解 20 能否清楚解释 IoC、Bean、AOP、事务、MVC
原理理解 20 能否讲清代理、生命周期、事务链路
编码能力 25 能否独立写出合理结构的 Spring Boot 项目
排错能力 15 能否系统定位 Bean、事务、MVC、配置问题
面试表达 20 回答是否结构化、能否结合场景和坑点

分档说明

  1. 90-100:中级达标,能讲原理、能做项目、能排错。
  2. 75-89:初级偏强,开发可用,原理还需巩固。
  3. 60-74:入门达标,但机制理解不稳。
  4. 60 以下:需要回到主干重新补基础。

9. 如何根据错误结果反向补课

错误表现 暴露的问题 回补阶段
说不清 Spring 是什么 整体认知不足 第一阶段
Bean、IoC、DI 混淆 核心概念不稳 第二阶段
解释不清事务为何生效 AOP/代理机制没吃透 第三阶段
听不懂后置处理器 底层主流程薄弱 第四阶段
项目结构混乱 工程实践不足 第五阶段
一遇报错就乱改注解 排错方法没建立 第六阶段
面试回答散乱 没形成表达模板 第七阶段

10. 下一步继续深入该学什么

当你完成这份手册后,建议按下面顺序继续:

  1. Spring Boot 深入:自动配置源码、Starter 机制。
  2. 数据访问:MyBatis / JPA、事务传播、锁与一致性。
  3. Spring Security:认证、授权、过滤器链。
  4. 缓存与消息:Redis、MQ 与 Spring 集成。
  5. 微服务:Spring Cloud、配置中心、服务治理。

最后建议

正确学习顺序再强调一次

  1. 先建立地图。
  2. 再学 IoC / Bean。
  3. 再学 AOP / 事务 / MVC。
  4. 再做工程实践。
  5. 再练排错。
  6. 最后整理面试表达。

企业里通常怎么用它

企业里最常见的组合是:

  1. Spring Boot 启动服务。
  2. Spring MVC 提供接口。
  3. Spring Transaction 管事务。
  4. MyBatis / JPA 做数据访问。
  5. Redis / MQ / Security 按业务需要扩展。

面试官通常怎么问它

面试官很少只问"定义",更常见的是:

  1. Spring 为什么能降低耦合?
  2. 事务底层怎么实现?
  3. AOP 和代理什么关系?
  4. 一次请求在 MVC 里怎么走?
  5. 你项目里 Spring 是怎么落地的?
  6. 你遇到过什么 Spring 问题,怎么排查?

实际开发最常踩的坑

  1. 包扫描范围不对导致 Bean 找不到。
  2. 同类型多个 Bean 冲突。
  3. @Transactional 自调用失效。
  4. 异常被吃掉导致不回滚。
  5. 把全部业务塞进 Controller。
  6. DTO、Entity、VO 混用。
  7. 配置环境切换混乱。

一句话收束

Spring 最值得你真正吃透的,不是注解数量,而是"容器、代理、MVC、工程化"这四条主线。

相关推荐
WZTTMoon2 小时前
VS Code Java开发配置与使用经验分享
java·vscode
语戚2 小时前
力扣 494. 目标和 —— 回溯 & 动态规划双解法全解(Java 实现)
java·算法·leetcode·动态规划·力扣·dp·回溯
YXWik62 小时前
Langchain4j(3) Prompt 提示词工程 + PromptTemplate + SystemMessage 高级用法
java·ai·prompt
StarShip2 小时前
JVM堆栈溢出监测原理
android·java
我不是程序猿儿2 小时前
【嵌入式】面向 STM32 的 ADC 与 DMA 学习路线
linux·stm32·单片机·嵌入式硬件·学习
阿荻在肝了2 小时前
Agent实践三:基于Chroma的RAG检索
python·学习·agent
徐子元竟然被占了!!2 小时前
数字证书学习
linux·网络·学习
北极的代码2 小时前
2026年Java后端热点科普:Java 26新特性+Java 21落地实战,解锁后端开发新范式
java·后端
lkforce2 小时前
MiniMind学习笔记--安装部署
笔记·python·学习·minimind