Skip to content

Spring 从零学习路线与核心原理总览 ​

Spring Framework 不是一组必须背诵的注解,而是一套围绕“对象怎样定义、创建、组装、增强、使用和销毁”建立的基础设施。@Autowired、@Transactional、@RequestMapping 只是入口;真正需要理解的是容器、代理和扩展链如何让这些注解产生行为。

本页是 Spring 栏目的课程入口。它不会重复每个专题的全部源码,而是解决三个学习问题:

  1. 为什么要学这一知识点;
  2. 它依赖前面什么原理;
  3. 学完后应当能完成什么 Demo 和排查任务。

学完后能够做什么 ​

  • 从 BeanDefinition 讲到最终代理对象;
  • 区分 IoC、DI、BeanFactory、ApplicationContext;
  • 选择构造器、Setter、字段、集合和延迟注入;
  • 解释 Bean 生命周期和后置处理器的插入位置;
  • 解释循环依赖、三级缓存和早期代理的边界;
  • 设计并实现 Spring 扩展点;
  • 从 JDK/CGLIB 代理讲到 MethodInterceptor 链;
  • 正确设计声明式和编程式事务边界;
  • 从 Servlet 请求讲到 Spring MVC JSON 响应;
  • 沿 refresh、doGetBean、doCreateBean 阅读源码;
  • 定位启动慢、依赖注入失败、代理失效、事务失效和请求异常;
  • 说明 JDK 7/8、Spring 5、Boot 2 与 Spring 6/Boot 3 的版本边界。

一、Spring 到底解决什么问题 ​

1.1 没有容器时的对象图 ​

假设订单服务依赖库存、支付、消息和审计:

java
public class OrderService {
    private final InventoryService inventoryService =
            new InventoryService(new JdbcInventoryRepository());
    private final PaymentService paymentService =
            new PaymentService(new BankHttpClient());
    private final NotificationService notificationService =
            new NotificationService(new RocketMqClient());
}

问题不是 new 本身错误,而是对象创建、配置、生命周期和业务流程被绑在一起:

  • 测试无法方便替换支付客户端;
  • 数据库 URL、超时和连接池配置散落;
  • 同一个客户端可能被重复创建;
  • 初始化失败和资源关闭没有统一位置;
  • 日志、事务、权限需要侵入每个业务方法;
  • 改用另一个实现必须修改业务类;
  • 很难观察完整对象依赖图。

1.2 IoC 后的职责划分 ​

业务类只声明依赖:

java
public class OrderService {
    private final InventoryService inventoryService;
    private final PaymentService paymentService;

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

容器负责:

  • 读取对象定义;
  • 选择实现;
  • 创建实例;
  • 解析依赖;
  • 执行初始化和销毁;
  • 应用后置处理器;
  • 必要时返回代理;
  • 管理 singleton、prototype 等作用域。

IoC 是控制权反转:业务不再掌控整个对象图。DI 是容器实现 IoC 的主要方式:把解析出的依赖传给构造器、字段或方法。

二、Spring 的核心心智模型 ​

mermaid
flowchart TD
    A["配置类、注解、XML或注册器"] --> B["BeanDefinition创建元数据"]
    B --> C["BeanFactory保存和处理定义"]
    C --> D["选择构造器或工厂方法实例化"]
    D --> E["解析并注入依赖"]
    E --> F["执行Aware和初始化回调"]
    F --> G["BeanPostProcessor检查并增强"]
    G --> H["可能生成AOP代理"]
    H --> I["最终Bean进入作用域缓存"]
    I --> J["业务通过容器中的引用调用"]
    J --> K["容器关闭并执行销毁回调"]

2.1 BeanDefinition 不是 Bean ​

BeanDefinition 是“如何创建”的元数据,可能记录:

  • Bean class;
  • 工厂 Bean 和工厂方法;
  • scope;
  • lazy;
  • primary;
  • dependsOn;
  • 构造参数;
  • PropertyValues;
  • init/destroy method;
  • qualifier 和角色等信息。

Bean 是依据定义创建的运行对象。定义阶段可以被注册器和 BFPP 修改;对象阶段可以被 BPP 注入和代理。混淆二者就无法理解自动配置、扩展点和源码顺序。

2.2 容器中拿到的不一定是原始对象 ​

业务注入的引用可能是:

  • 普通原始 Bean;
  • JDK 动态代理;
  • CGLIB 类代理;
  • Lazy 代理;
  • ScopedProxy;
  • FactoryBean 创建的产品;
  • 多层代理的最外层对象。

因此不能用 bean.getClass() == Implementation.class 作为通用判断,也不能认为对 this 的调用会再次经过外部代理。

三、Spring Framework、Boot、MVC、Cloud 的关系 ​

名称解决的主要问题是否等同Spring核心容器
Spring FrameworkIoC、AOP、事务、Web、数据访问、测试等基础能力是基础主体
Spring MVC基于Servlet的Web MVC请求处理Framework的Web模块
Spring Boot自动配置、Starter、内嵌容器和生产支持建立在Framework上
Spring Security认证、授权和安全过滤器链独立生态项目,集成Framework
Spring Data统一数据访问抽象独立生态项目
Spring Cloud分布式系统组件抽象和集成建立在Boot生态上
Spring AI模型、Prompt、RAG、Tool等AI应用抽象建立在Boot生态上

学习顺序应先 Framework,再 Boot,再进入 Security、Cloud、AI。不了解 Bean、代理和自动配置扩展链,后面的注解只能停留在使用层。

四、学习前置知识 ​

开始 Spring 前至少应理解:

  • Java 类、接口、继承和组合;
  • 构造器和方法重载;
  • 注解与反射;
  • 泛型;
  • 异常和 cause 链;
  • 集合与线程安全基础;
  • JDBC 事务基本概念;
  • HTTP 请求、响应和 Servlet 基础;
  • Maven 依赖与 classpath。

不要求先读 Spring 源码,但如果连接口实现、代理对象、反射调用和线程本地变量都不了解,学习 AOP 与事务会变成背结论。对应前置可从 JavaSE、JavaEE 栏目补齐。

五、完整学习路线 ​

mermaid
flowchart TD
    A["阶段0:Java与Servlet前置"] --> B["阶段1:IoC与BeanDefinition"]
    B --> C["阶段2:依赖注入与生命周期"]
    C --> D["阶段3:循环依赖、Lazy与作用域"]
    D --> E["阶段4:容器扩展点"]
    E --> F["阶段5:AOP与代理调用链"]
    F --> G["阶段6:事务边界与传播"]
    G --> H["阶段7:Spring MVC请求链"]
    H --> I["阶段8:refresh与Bean创建源码"]
    I --> J["阶段9:Spring Boot自动配置"]
    J --> K["商业场景与生产排查"]
    K --> L["验收与面试"]

路线不是按照注解数量排列,而是按照原理依赖关系排列:代理必须建立在容器创建对象之上,事务必须建立在代理调用之上,Boot 自动配置必须建立在定义注册和条件装配之上。

六、阶段一:IoC、BeanFactory 与 ApplicationContext ​

为什么先学 ​

后续所有能力都要求对象进入 Spring 容器。手工 new 的对象不会自动获得注入、事务、缓存或安全切面。

必须掌握 ​

  • IoC 与 DI 的区别;
  • BeanDefinition 怎样注册;
  • BeanFactory 与 ApplicationContext;
  • refresh() 主要阶段;
  • getBean() 主线;
  • singleton、prototype 和自定义 scope;
  • FactoryBean 与 BeanFactory;
  • 父子容器;
  • @Configuration 与 @Bean。

最低实践 ​

不用 Spring Boot,使用 AnnotationConfigApplicationContext 创建接口实现、注入 Service、取得 Bean 并关闭容器。

如果跳过 ​

会把 @Autowired 当成 Java 语法,把 Boot 自动配置当成扫描魔法,无法解释为什么手工 new 导致事务失效。

进入课程:Spring IoC容器与依赖注入全过程。

七、阶段二:依赖注入与 Bean 生命周期 ​

必须掌握 ​

  • 构造器、Setter、字段和方法注入;
  • @Autowired 候选算法;
  • @Resource 名称解析;
  • Primary、Qualifier、泛型和集合注入;
  • Optional、Nullable、ObjectProvider;
  • 实例化、属性填充和初始化的区别;
  • Aware、PostConstruct、InitializingBean、init-method;
  • PreDestroy、DisposableBean、destroy-method;
  • BeanPostProcessor 前后置回调。

为什么推荐构造器注入 ​

  • 强制依赖在创建时完整;
  • 字段可 final;
  • 测试可直接 new;
  • 依赖关系可见;
  • 构造器循环依赖会立即暴露设计问题。

如果不会会怎样 ​

  • 构造器中读取字段注入值为 null;
  • 多个实现时注入错误对象;
  • JDK 代理导致具体类型注入失败;
  • 初始化方法做重活导致启动慢;
  • 关闭时线程池和连接未释放。

进入课程:

八、阶段三:循环依赖、Lazy 与作用域 ​

必须掌握 ​

  • 构造器循环为什么无法提前暴露;
  • singleton 三级缓存;
  • earlyBeanReference 与早期代理;
  • prototype 循环边界;
  • Boot 默认循环依赖策略;
  • 定义级 Lazy 与注入点 Lazy 代理;
  • singleton 注入 prototype;
  • ObjectProvider 与 ScopedProxy。

关键原则 ​

容器能解决一部分循环依赖,不代表设计合理。优先通过职责拆分、协调服务或事件建立单向依赖。Lazy 代理只改变创建时机,也可能把启动错误推迟到真实流量。

进入课程:

九、阶段四:Spring 扩展点 ​

为什么要学 ​

Spring Boot Starter、自动配置、MyBatis Mapper、事务、AOP、配置绑定和框架集成,都依赖 Spring 扩展链。只会写 Service 和 Controller,无法设计可复用基础设施。

按生命周期掌握 ​

阶段扩展点操作对象
注册定义BeanDefinitionRegistryPostProcessorBeanDefinition注册表
修改定义BeanFactoryPostProcessorBeanDefinition/BeanFactory
实例前后InstantiationAwareBeanPostProcessorBean创建过程
初始化前后BeanPostProcessorBean实例/代理
特殊产品FactoryBean复杂产品对象
配置导入ImportSelector/Registrar配置和定义
事件ApplicationEventPublisher/Listener事件通知
容器启停Lifecycle/SmartLifecycle生命周期组件

如果选错扩展点 ​

  • BFPP 中获取普通 Bean,导致过早创建;
  • BPP 保存请求状态,产生线程安全问题;
  • FactoryBean 工厂和产品类型混淆;
  • 监听器执行长任务拖慢发布线程;
  • ImportSelector 做远程 I/O 导致启动不可控。

进入课程:Spring核心扩展点与Starter扩展链全过程。

十、阶段五:AOP 与代理调用链 ​

必须掌握 ​

  • Aspect、Advisor、Pointcut、Advice;
  • AutoProxyCreator;
  • JDK 动态代理和 CGLIB;
  • MethodInterceptor 与 proceed();
  • 多切面顺序;
  • Before、After、Around 的异常和返回语义;
  • 自调用为什么绕过代理;
  • final/private/static 限制;
  • 早期代理与循环依赖;
  • AOP 与 AspectJ 的边界。

核心链路 ​

mermaid
flowchart TD
    A["目标Bean完成初始化"] --> B["AutoProxyCreator查找Advisor"]
    B --> C{"Pointcut匹配?"}
    C -- "否" --> D["返回原始Bean"]
    C -- "是" --> E["ProxyFactory创建代理"]
    E --> F["业务持有代理引用"]
    F --> G["外部方法调用进入代理"]
    G --> H["MethodInterceptor链"]
    H --> I["调用目标方法"]
    I --> J["按调用栈反向退出增强"]

如果不会会怎样 ​

  • 认为加了注解一定生效;
  • this.method() 导致事务和缓存失效;
  • Around 忘记 proceed() 让业务不执行;
  • 调用两次 proceed() 造成重复扣款;
  • 吞异常改变事务回滚;
  • 按实现类注入 JDK 代理失败。

进入课程:Spring AOP代理与拦截器链全过程。

十一、阶段六:Spring 事务 ​

必须掌握 ​

  • 声明式事务与编程式事务;
  • TransactionInterceptor;
  • PlatformTransactionManager;
  • 逻辑事务与物理事务;
  • REQUIRED、REQUIRES_NEW、NESTED;
  • rollback-only 与 UnexpectedRollbackException;
  • checked exception 回滚规则;
  • 事务同步和线程绑定资源;
  • MyBatis/JPA 如何加入同一事务;
  • afterCommit 为什么不能保证消息可靠;
  • 连接池、锁和事务超时。

商业边界 ​

数据库事务不能自动覆盖 MQ、Redis、ES 和远程服务。跨资源一致性要结合本地消息表、事务消息、CDC、补偿或分布式事务方案。

如果不会会怎样 ​

  • 自调用导致事务不生效;
  • catch 异常后错误提交;
  • REQUIRES_NEW 耗尽连接池;
  • 长事务持锁导致高并发阻塞;
  • afterCommit 发送 MQ 仍然丢消息;
  • 异步线程丢失事务上下文。

进入课程:

十二、阶段七:Spring MVC ​

必须掌握 ​

  • Servlet 容器和 Spring 容器边界;
  • DispatcherServlet 初始化;
  • HandlerMapping 与 HandlerAdapter;
  • RequestMapping 注册和匹配;
  • 参数解析、转换、绑定和校验;
  • HttpMessageConverter;
  • Content-Type、Accept、415和406;
  • ReturnValueHandler;
  • HandlerInterceptor;
  • HandlerExceptionResolver;
  • Callable、DeferredResult 与异步重派发;
  • response committed。

如果不会会怎样 ​

面对 400、404、415、406 或 Controller 返回后的 500,不知道问题发生在网关、映射、参数、业务、序列化还是响应提交阶段。

进入课程:Spring MVC请求执行链与扩展点全过程。

十三、阶段八:Spring 容器源码 ​

阅读顺序 ​

  1. AbstractApplicationContext.refresh();
  2. invokeBeanFactoryPostProcessors();
  3. registerBeanPostProcessors();
  4. preInstantiateSingletons();
  5. doGetBean();
  6. createBean();
  7. doCreateBean();
  8. populateBean();
  9. initializeBean();
  10. close() 与 destroySingletons()。

源码学习的目标不是背行号,而是能用调用栈解释注入、代理、缓存和回滚。

进入课程:Spring容器启动与Bean创建源码执行链。

十四、阶段九:Spring Boot ​

Framework 掌握后再进入 Boot:

  • SpringApplication 启动;
  • 环境和配置文件;
  • 自动配置候选导入;
  • @Conditional;
  • Starter;
  • 配置属性绑定;
  • 内嵌 Tomcat;
  • Actuator;
  • 日志、异常和校验;
  • 自定义自动配置与 Starter;
  • 启动诊断和生产部署。

Boot 没有替代 Spring Framework,它自动组装 Framework 的 BeanDefinition 和基础设施。进入课程:Spring Boot从零到生产级掌握。

十五、一个商业请求怎样串起全部知识 ​

以“创建订单并可靠通知”为例:

mermaid
flowchart TD
    A["HTTP请求进入Filter链"] --> B["DispatcherServlet匹配Controller"]
    B --> C["参数转换、绑定和校验"]
    C --> D["Controller调用OrderService代理"]
    D --> E["TransactionInterceptor开启事务"]
    E --> F["OrderService调用Repository"]
    F --> G["写订单和本地消息表"]
    G --> H["事务提交"]
    H --> I["异步任务投递MQ"]
    I --> J["消费者幂等处理"]
    J --> K["失败重试和补偿"]

这里同时用到:

  • IoC:Controller、Service、Repository和客户端由容器组装;
  • 生命周期:连接池和客户端统一初始化、关闭;
  • AOP:事务拦截器包围 Service 方法;
  • 事务:订单与本地消息在一个数据库事务;
  • MVC:JSON 解析、校验和响应;
  • 扩展点:异常处理、参数解析、事件或自定义 Starter;
  • Boot:自动配置数据源、MVC、Jackson和监控。

如果只学会注解写法而不懂这些连接关系,线上出现自调用、消息丢失、序列化异常或关闭丢任务时就无法定位。

十六、Spring 模块导航地图 ​

想解决的问题首先阅读深入阅读
对象为什么由容器创建IoC全过程容器源码
字段为什么没注入Autowired与Resource生命周期
多实现怎样选择Autowired候选算法IoC依赖解析
Bean何时初始化和销毁Bean生命周期源码initializeBean
为什么首次调用才创建Lazy全过程preInstantiateSingletons
循环依赖为何有时成功循环依赖三级缓存源码
怎样开发基础组件核心扩展点后置处理器源码
事务和日志为何依赖代理AOP全过程AOP接入Bean创建
事务为何失效事务全过程AOP自调用
请求为何返回400/415/406Spring MVCMVC生产Runbook
启动为什么慢源码启动排查Lazy风险
面试如何组织回答Spring面试页对应原理锚点

十七、版本选择与常见区别 ​

技术线Java基线包体系与特点
Spring 4.x常见JDK 7/8传统存量项目,部分现代API尚未出现
Spring 5.3JDK 8+重要长期存量线,本文主要验证基线
Spring Boot 2.7JDK 8+Boot 2末代主线之一,仍使用javax生态
Spring 6Java 17+Jakarta EE 9+,Servlet等迁到jakarta包
Spring Boot 3Java 17+基于Spring 6和Jakarta,不兼容JDK 8

JDK 7/8 学习重点 ​

  • 普通 POJO,不使用 record;
  • JDK 8 lambda 可用,但教学 Demo 应说明版本;
  • javax.annotation.Resource、javax.servlet、javax.validation 常见;
  • Spring 5.3 与 Boot 2.7 是常见兼容组合;
  • JDK 11 后部分 Java EE API 从 JDK 移除,需要显式依赖;
  • Spring 6 不能通过只改 import 在 JDK 8 上运行。

迁移时必须同时评估 JDK、Spring、Boot、Servlet容器、Validation、JPA、Security和第三方 Starter,不能单独升级一个坐标。

十八、第一个 JDK 8 可运行 Spring Demo ​

这个 Demo 不依赖 Spring Boot,先证明 BeanDefinition、构造器注入、singleton 和销毁。金额使用 BigDecimal,避免商业金额使用 double 或 float。

18.1 Maven依赖 ​

xml
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.39</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.11.0</version>
            <configuration>
                <source>8</source>
                <target>8</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
    </plugins>
</build>

18.2 完整代码 ​

java
import java.math.BigDecimal;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

public class SpringFirstDemo {
    interface PaymentGateway {
        String pay(String orderId, BigDecimal amount);
    }

    static class MockPaymentGateway implements PaymentGateway,
            DisposableBean {
        public String pay(String orderId, BigDecimal amount) {
            return "PAID:" + orderId + ":" + amount.toPlainString();
        }

        public void destroy() {
            System.out.println("paymentGateway closed");
        }
    }

    static class OrderService {
        private final PaymentGateway paymentGateway;

        OrderService(PaymentGateway paymentGateway) {
            this.paymentGateway = paymentGateway;
        }

        String checkout(String orderId, BigDecimal amount) {
            if (amount == null || amount.signum() <= 0) {
                throw new IllegalArgumentException("amount必须大于0");
            }
            return paymentGateway.pay(orderId, amount);
        }
    }

    @Configuration
    static class Config {
        @Bean
        PaymentGateway paymentGateway() {
            return new MockPaymentGateway();
        }

        @Bean
        OrderService orderService(PaymentGateway gateway) {
            return new OrderService(gateway);
        }
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(Config.class);
        try {
            OrderService first = context.getBean(OrderService.class);
            OrderService second = context.getBean(OrderService.class);
            if (first != second) {
                throw new AssertionError("默认scope应为singleton");
            }
            String result = first.checkout(
                    "ORDER-1001", new BigDecimal("99.90"));
            if (!"PAID:ORDER-1001:99.90".equals(result)) {
                throw new AssertionError(result);
            }
            System.out.println(result);
            System.out.println("singleton=" + (first == second));
        } finally {
            context.close();
        }
    }
}

期望输出:

text
PAID:ORDER-1001:99.90
singleton=true
paymentGateway closed

18.3 每一步发生了什么 ​

  1. 配置类先作为 BeanDefinition 注册;
  2. ConfigurationClassPostProcessor 解析两个 @Bean 方法;
  3. paymentGateway 和 orderService 成为工厂方法定义;
  4. 启动预实例化 singleton;
  5. 创建 OrderService 前先解析 PaymentGateway 参数;
  6. 调用 paymentGateway() 创建网关;
  7. 调用 orderService(gateway) 完成构造器注入;
  8. 两次 getBean 命中同一 singleton;
  9. 业务方法使用 BigDecimal 支付;
  10. context.close 触发 DisposableBean.destroy。

这个 Demo 没有 AOP、事务和 MVC,目的是先验证容器最小主线。继续学习时逐层增加能力,每增加一层都能解释它在哪里接入。

十九、从最小 Demo 逐步扩展 ​

练习修改内容证明什么
练习1增加第二个PaymentGateway多候选与Qualifier
练习2增加PostConstruct和destroy生命周期顺序
练习3把Gateway改prototypescope差异
练习4注入ObjectProvider每次获取prototype
练习5增加自定义BeanPostProcessor实例扩展点
练习6增加Aspect代理和拦截器链
练习7增加H2和TransactionTemplate编程式事务
练习8增加Transactional声明式事务与自调用
练习9增加Spring MVCHTTP到Service调用链
练习10改为Spring Boot自动配置与内嵌容器

二十、商业项目设计原则 ​

  • Controller 只接收、校验和转换响应,业务放 Service;
  • 写操作明确事务边界,不把远程长调用无脑放进事务;
  • 强制依赖优先构造器注入;
  • singleton Service 不保存当前请求可变状态;
  • BFPP/BPP 不执行无超时远程 I/O;
  • Bean 初始化和销毁必须有超时、幂等和异常处理;
  • 面向接口,但接口应表达真实替换边界,不为每个类机械建接口;
  • 自定义扩展点要明确顺序、线程安全和作用范围;
  • AOP 切面不能吞异常或意外修改业务返回;
  • 日志不输出密码、token、密钥、身份证和医疗敏感数据;
  • 金额使用 BigDecimal;
  • 时间明确时区;
  • 核心能力启动失败应阻止实例接流量;
  • 非核心 Lazy 能力要有预热、首调指标和降级。

二十一、常见误区与后果 ​

误区后果正确方向
Spring就是Autowired不懂定义、生命周期和代理从BeanDefinition开始
加注解一定生效手工new、自调用、条件不匹配时失效确认对象来源和调用入口
接口越多越解耦无意义抽象增加维护成本围绕替换和业务边界抽象
字段注入最方便所以最好隐藏依赖、难测试、构造时不完整强制依赖优先构造器
能解决循环依赖就不用重构双向耦合长期存在建立单向依赖
AOP等于AspectJ混淆代理与字节码织入先掌握Spring代理AOP
Transactional覆盖所有资源MQ、Redis、ES仍可能不一致设计跨资源一致性
全局Lazy能优化启动错误和耗时转移到首个请求找启动慢根因并预热
Controller返回就代表成功序列化和网络写出仍可能失败覆盖返回值处理与监控
会背源码方法名就算掌握遇到线上问题仍不会定位用断点和Demo验证状态变化

二十二、生产问题应该从哪里进入 ​

现象第一检查页
NoSuch/NoUnique/UnsatisfiedDependency依赖注入异常诊断
启动很慢或卡死容器启动慢Runbook
Bean没有代理代理缺失排查
Transactional不生效Spring事务
首次请求突然很慢Lazy生产排查
BeanCurrentlyInCreation循环依赖
HTTP 400/404/415/406/500MVC错误阶段表
关闭卡住或资源未释放容器关闭源码

二十三、怎样判断自己真正掌握 ​

不能只回答“Spring 核心是 IoC 和 AOP”。至少应能够:

  • 手写完整可运行容器 Demo;
  • 画出 BeanDefinition 到最终代理的流程;
  • 解释构造器和字段注入的不同阶段;
  • 分析多个候选的选择结果;
  • 解释 FactoryBean 的 &;
  • 解释定义级和注入点 Lazy;
  • 画三级缓存和早期代理;
  • 编写一个安全的 BPP 或 ImportSelector;
  • 解释 MethodInterceptor 洋葱调用;
  • 复现自调用事务失效;
  • 区分 REQUIRED、REQUIRES_NEW 和 NESTED;
  • 从 Content-Type 与 Accept 区分 415、406;
  • 用断点追踪 refresh 和 doCreateBean;
  • 用线程栈和 JFR 定位启动卡死;
  • 说明 JDK 8 与 Spring 6 的不兼容边界。

完整验收请进入:Spring从零到精通验收清单。

二十四、面试回答组织方法 ​

回答原理题按以下顺序:

text
一句话定义
    ↓
为什么需要
    ↓
核心参与者
    ↓
完整执行流程
    ↓
版本和适用边界
    ↓
不这样会怎样
    ↓
商业项目使用
    ↓
生产排查方法

例如回答 @Transactional,不能只说“基于 AOP”:还要说明代理创建、TransactionInterceptor、事务管理器、线程绑定资源、传播行为、提交回滚、自调用、异常规则、连接池风险和跨资源一致性边界。

面试标准回答集中在:Spring面试知识点。详细原理保留在各知识页,面试页通过锚点跳回来。

二十五、推荐学习顺序清单 ​

  1. 当前总览页;
  2. 从零到生产级掌握;
  3. IoC容器与依赖注入;
  4. Bean生命周期;
  5. @Autowired与@Resource;
  6. Lazy;
  7. 循环依赖;
  8. 核心扩展点;
  9. AOP代理与拦截器链;
  10. Spring事务;
  11. Spring MVC;
  12. 容器源码执行链;
  13. Spring Boot;
  14. 从零到精通验收清单;
  15. Spring面试知识点。

学习时每完成一页,都应运行 Demo、故意制造至少一个错误、根据异常和日志定位,再进入下一页。只看不运行,很难形成对容器状态和调用链的真实理解。