Spring Boot 面试知识(一):从启动流程到 AOP 与事务失效

本文从面试视角梳理 Spring Boot 启动流程、自动配置、IOC/DI、Bean 生命周期、Spring MVC、AOP、动态代理、@Transactional 以及事务失效场景。

重点不是孤立地背概念,而是理解这些机制如何串成一条完整调用链。

摘要

Spring Boot 面试题看起来很多,但底层主线并不复杂:

  1. SpringApplication.run() 启动应用并刷新 Spring 容器;
  2. 自动配置和组件扫描注册 BeanDefinition;
  3. IOC 容器创建 Bean,通过 DI 完成对象组装;
  4. Bean 初始化过程中,后置处理器可能为对象创建 AOP 代理;
  5. Web 请求由 Spring MVC 分发到 Controller;
  6. Controller 调用 Service 代理,事务拦截器在业务方法前后开启、提交或回滚事务。

只要抓住"容器、Bean、代理、调用边界"这几个关键词,大部分 Spring 面试追问都能顺着原理回答。

关键词: Spring Boot、IOC、DI、Bean 生命周期、Spring MVC、AOP、动态代理、事务、面试

图片说明:一二和布布带我们沿着 启动 → 自动配置 → IOC/DI → Bean 生命周期 → MVC → AOP/动态代理 → 事务 的顺序,串起 Spring Boot 的核心面试知识。


一、Spring Boot 启动流程

1. 面试时先给结论

SpringApplication.run() 的主要工作可以概括为四步:

  1. 准备运行环境 Environment
  2. 创建合适的 ApplicationContext
  3. 调用 refresh() 刷新容器,完成配置解析、Bean 创建和 Web Server 启动;
  4. 执行 Runner,发布应用就绪事件。

面试官真正想听到的关键词,通常是:

text 复制代码
SpringApplication.run()
        ↓
准备 Environment
        ↓
创建 ApplicationContext
        ↓
refresh() 刷新容器
        ↓
解析配置、注册并创建 Bean
        ↓
启动内嵌 Web Server
        ↓
执行 Runner,应用就绪

2. 启动入口

java 复制代码
@SpringBootApplication
public class OrderApplication {

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

表面上只调用了一行代码,背后主要经历以下阶段。

3. 创建 SpringApplication

Spring Boot 会记录主配置类,并推断当前应用类型:

  • Servlet Web 应用;
  • Reactive Web 应用;
  • 非 Web 应用。

同时,还会准备启动过程中需要使用的初始化器和监听器。

4. 准备 Environment

Boot 会加载并整理配置来源,例如:

  • 命令行参数;
  • JVM 系统属性;
  • 操作系统环境变量;
  • application.properties
  • application.yml
  • Profile 对应的配置文件。

这些配置最终被组合到 Environment 中,后续的属性绑定和条件装配都会依赖它。

5. 创建 ApplicationContext

Spring Boot 会根据应用类型创建对应的上下文,然后完成以下工作:

  • 关联 Environment
  • 执行 ApplicationContextInitializer
  • 注册主配置类;
  • 准备进入容器刷新阶段。

6. 核心:refresh()

Spring Boot 启动的核心,最终会落到 Spring Framework 的:

java 复制代码
AbstractApplicationContext#refresh

这个方法负责真正刷新 IOC 容器。面试时不必背完整源码,但要知道几个重要阶段:

  1. 准备 BeanFactory;
  2. 执行 BeanFactoryPostProcessor
  3. 解析配置类、组件扫描、@Import 和自动配置;
  4. 注册 BeanPostProcessor
  5. 初始化事件广播器等基础组件;
  6. 创建非懒加载单例 Bean;
  7. 启动内嵌 Web Server;
  8. 完成刷新并发布事件。

其中,ConfigurationClassPostProcessor 非常关键,它负责处理:

  • @Configuration
  • @ComponentScan
  • @Import
  • @Bean

自动配置类也是通过配置解析流程进入 Spring 容器的。

7. 应用启动完成

容器刷新完成后,Spring Boot 会执行:

  • ApplicationRunner
  • CommandLineRunner

然后发布 ApplicationReadyEvent,表示应用已经可以对外提供服务。如果启动失败,则会发布 ApplicationFailedEvent

8. 高频追问:两种后置处理器有什么区别

BeanFactoryPostProcessor

处理的是 BeanDefinition,也就是 Bean 的"创建说明书"。执行时,大部分普通 Bean 还没有实例化。

BeanPostProcessor

处理的是已经实例化的 Bean 对象,可以在 Bean 初始化前后执行增强,甚至返回另一个对象。Spring AOP 创建代理就是典型应用。

一句话记忆:

BeanFactoryPostProcessor 修改 Bean 定义,BeanPostProcessor 处理 Bean 实例。


二、自动配置原理

1. @SpringBootApplication 包含什么

@SpringBootApplication 主要组合了三个注解:

java 复制代码
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan

它们分别负责:

注解 作用
@SpringBootConfiguration 标识 Spring Boot 主配置类
@EnableAutoConfiguration 开启自动配置
@ComponentScan 扫描并注册业务组件

因为 @ComponentScan 默认从启动类所在包向下扫描,所以启动类通常应该放在项目根包。

2. 自动配置类从哪里加载

@EnableAutoConfiguration 通过 @Import 机制导入自动配置选择器。

现代 Spring Boot 主要从依赖包中的以下文件读取自动配置候选类:

text 复制代码
META-INF/spring/
org.springframework.boot.autoconfigure.AutoConfiguration.imports

旧版本面经中经常提到:

text 复制代码
META-INF/spring.factories

这是历史版本的重要实现,但面试现代 Spring Boot 时,只回答 spring.factories 已经不够完整。

3. 为什么引入 starter 就能使用功能

严格来说,starter 通常只是一个依赖聚合器。真正注册默认 Bean 的,是对应的 auto-configure 模块。

自动配置类通常类似下面这样:

java 复制代码
@AutoConfiguration
@ConditionalOnClass(DataSource.class)
public class MyDataSourceAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public DataSource dataSource() {
        return new DefaultDataSource();
    }
}

它表达的含义是:

  1. classpath 中存在 DataSource
  2. 用户没有自己注册 DataSource
  3. Spring Boot 才提供默认实现。

4. 常见条件注解

注解 生效条件
@ConditionalOnClass classpath 中存在指定类
@ConditionalOnMissingClass classpath 中不存在指定类
@ConditionalOnBean 容器中存在指定 Bean
@ConditionalOnMissingBean 容器中不存在指定 Bean
@ConditionalOnProperty 配置属性满足要求
@ConditionalOnWebApplication 当前属于 Web 应用

自动配置最重要的设计原则是:

提供合理默认值,但优先尊重用户配置。

例如,自动配置方法带有 @ConditionalOnMissingBean 时,只要用户自己定义了同类型 Bean,默认配置就会退让。

5. 自动配置没有生效怎么排查

可以按照以下顺序检查:

  1. 使用 --debug 或配置 debug=true 查看条件评估报告;
  2. 检查目标类是否真的在 classpath;
  3. 检查配置属性是否满足条件;
  4. 检查容器中是否已经存在同类型 Bean;
  5. 检查是否通过注解或配置排除了自动配置类;
  6. 使用 Actuator 的 conditions 端点进一步分析。

三、IOC 与 DI

1. IOC 是思想,DI 是实现方式

IOC,Inversion of Control,中文通常叫控制反转。

它指的是:对象的创建、组装和生命周期管理,不再由业务代码主动完成,而是交给 Spring 容器。

DI,Dependency Injection,中文叫依赖注入。

它是 IOC 最常见的实现方式:Spring 创建对象后,把对象需要的依赖注入进去。

传统写法:

java 复制代码
public class OrderService {

    private final OrderRepository repository =
            new JdbcOrderRepository();
}

使用依赖注入:

java 复制代码
@Service
public class OrderService {

    private final OrderRepository repository;

    public OrderService(OrderRepository repository) {
        this.repository = repository;
    }
}

前者由 OrderService 主动创建依赖,后者只声明自己需要什么,由容器负责提供。

2. 为什么推荐构造器注入

Spring 支持三种常见注入方式:

  • 构造器注入;
  • Setter 注入;
  • 字段注入。

业务代码优先推荐构造器注入,因为它:

  • 能明确表达必需依赖;
  • 可以将字段声明为 final
  • 对象创建完成后就是可用状态;
  • 单元测试时可以直接构造对象;
  • 更容易暴露循环依赖;
  • 构造参数过多时,会提醒我们类的职责可能过重。

如果类只有一个构造器,通常不必添加 @Autowired

3. 一个接口有多个实现怎么办

例如:

java 复制代码
public interface PayStrategy {
    void pay();
}

存在多个实现时,可以使用:

  • @Primary:指定默认实现;
  • @Qualifier:指定具体候选 Bean;
  • List<PayStrategy>:注入所有实现;
  • Map<String, PayStrategy>:按 Bean 名称获取所有实现。

后两种方式特别适合策略模式。

4. 循环依赖怎么回答

首先要明确:循环依赖通常是设计问题,优先考虑拆分职责。

在允许循环引用的前提下,Spring 可以借助三级缓存和提前暴露引用,解决一部分基于字段或 Setter 注入的单例循环依赖。

但构造器循环依赖通常无法解决:

text 复制代码
创建 A 需要 B
创建 B 又需要 A

此时 A 和 B 都无法先完成实例化。

所谓三级缓存,主要保存:

  1. 已经完整初始化的单例;
  2. 提前暴露的单例对象;
  3. 可以创建早期引用的对象工厂。

第三层工厂的重要意义之一,是让 Spring 有机会提前暴露代理引用,减少其他 Bean 拿到裸对象而最终容器中保存代理对象的不一致问题。

不要把三级缓存回答成:

Spring 可以解决所有循环依赖。

这是错误的。


四、Bean 生命周期

1. 标准生命周期

以普通 singleton Bean 为例:

text 复制代码
注册 BeanDefinition
        ↓
实例化 Bean
        ↓
属性填充、依赖注入
        ↓
Aware 回调
        ↓
BeanPostProcessor 初始化前处理
        ↓
执行初始化方法
        ↓
BeanPostProcessor 初始化后处理
        ↓
Bean 可以使用
        ↓
容器关闭时执行销毁方法

展开回答如下:

  1. Spring 根据 BeanDefinition 实例化对象;
  2. 完成属性填充和依赖注入;
  3. 调用 BeanNameAwareBeanFactoryAware 等 Aware 回调;
  4. 执行 postProcessBeforeInitialization()
  5. 执行 Bean 初始化回调;
  6. 执行 postProcessAfterInitialization()
  7. 如果匹配 AOP 规则,这里可能返回代理对象;
  8. 容器关闭时执行销毁回调。

2. 初始化方法的顺序

常见顺序为:

text 复制代码
@PostConstruct
        ↓
InitializingBean.afterPropertiesSet()
        ↓
自定义 init-method

销毁方法的常见顺序为:

text 复制代码
@PreDestroy
        ↓
DisposableBean.destroy()
        ↓
自定义 destroy-method

业务代码通常优先使用 @PostConstruct@PreDestroy 或自定义方法,避免直接耦合 Spring 生命周期接口。

3. AOP 代理在哪一步产生

自动代理创建器属于 BeanPostProcessor

它会判断当前 Bean 是否匹配某个 Advisor。如果匹配,就会包装目标对象并返回代理对象。其他 Bean 最终注入到的,可能不是原始对象,而是代理对象。

这也解释了为什么不应该在 @PostConstruct 中依赖 @Transactional:Bean 此时仍处于初始化过程,不能假设完整代理已经成为外部调用入口。

4. prototype Bean 会自动销毁吗

Spring 负责 prototype Bean 的创建和初始化,但把它交给调用者后,通常不会继续跟踪其完整生命周期。

因此,prototype Bean 不会像 singleton Bean 一样,在容器关闭时自动执行完整销毁流程。资源释放通常需要调用方自己负责。


五、Spring MVC 请求流程

1. 核心组件:DispatcherServlet

Spring MVC 基于 Servlet API,使用前端控制器模式。所有匹配的请求统一进入 DispatcherServlet,再由它协调其他组件处理。

一条典型请求链路如下:

text 复制代码
客户端请求
   ↓
Filter Chain
   ↓
DispatcherServlet
   ↓
HandlerMapping 查找处理器
   ↓
HandlerAdapter 调用 Controller
   ↓
Controller 调用 Service
   ↓
返回值处理 / 异常处理
   ↓
JSON 响应或视图渲染

2. 详细处理过程

  1. 请求首先经过 Servlet Filter;
  2. DispatcherServlet 接收请求;
  3. HandlerMapping 查找 Handler 和对应拦截器;
  4. 返回 HandlerExecutionChain
  5. DispatcherServlet 选择对应的 HandlerAdapter
  6. 参数解析器把请求参数转换成 Controller 方法参数;
  7. HandlerAdapter 调用 Controller;
  8. 返回值处理器处理 Controller 返回值;
  9. HttpMessageConverter 将对象序列化为 JSON,或者由 ViewResolver 解析页面;
  10. 异常交给 HandlerExceptionResolver 体系处理。

3. HandlerMappingHandlerAdapter 为什么分开

  • HandlerMapping 负责找到谁处理请求;
  • HandlerAdapter 负责使用什么方式调用它。

不同类型的 Handler 可能拥有不同调用方式。通过适配器模式,DispatcherServlet 不需要了解所有 Handler 的具体实现。

4. Filter、Interceptor、AOP 的区别

机制 工作层次 典型处理范围 常见用途
Filter Servlet 容器层 匹配的 HTTP 请求 编码、CORS、安全、请求包装
Interceptor Spring MVC 层 Handler 调用前后 登录校验、接口审计、MVC 上下文
AOP Spring Bean 方法层 匹配切点的方法 事务、日志、权限、重试、指标

六、AOP 与动态代理

1. AOP 解决什么问题

事务、日志、鉴权、监控等逻辑往往分散在许多业务模块中。

如果每个方法都手动编写这些代码,会产生大量重复。AOP 将横跨多个模块的逻辑提取成切面,再统一织入目标方法。

2. AOP 核心术语

术语 含义
Aspect 切面,切点和增强逻辑的组合
Join Point 连接点,Spring AOP 中主要指方法执行
Pointcut 切点,决定增强哪些方法
Advice 增强逻辑
Target 原始目标对象
Proxy 包装目标对象的代理对象
Advisor Pointcut 与 Advice 的组合

Advice 常见类型包括:

  • Before;
  • After Returning;
  • After Throwing;
  • After;
  • Around。

3. @Around 示例

java 复制代码
@Aspect
@Component
public class TimingAspect {

    @Around("execution(* com.example.order..*(..))")
    public Object timing(ProceedingJoinPoint point) throws Throwable {
        long start = System.nanoTime();
        try {
            return point.proceed();
        } finally {
            long cost = System.nanoTime() - start;
            System.out.println("cost=" + cost);
        }
    }
}

多个切面匹配同一个方法时,会形成拦截器链。调用过程类似一层层包裹的洋葱。

4. JDK 动态代理

JDK 动态代理基于接口,核心是 InvocationHandler

java 复制代码
OrderService proxy = (OrderService) Proxy.newProxyInstance(
        OrderService.class.getClassLoader(),
        new Class<?>[]{OrderService.class},
        (proxyObject, method, args) -> {
            System.out.println("before");
            try {
                return method.invoke(target, args);
            } finally {
                System.out.println("after");
            }
        }
);

客户端调用的是代理对象。代理先执行增强逻辑,然后再调用目标对象。

5. CGLIB 类代理

CGLIB 会动态生成目标类的子类,通过重写可覆盖的方法完成拦截,因此目标类不一定需要实现接口。

但类代理存在限制:

  • final 类不能被继承;
  • final 方法不能被重写;
  • private 方法不能被子类重写。

因此,这些位置无法使用常规 CGLIB 类代理完成增强。

6. Spring Framework 与 Spring Boot 的默认代理选择

Spring Framework 的基础代理规则通常描述为:

  • 目标对象实现接口时,可以使用 JDK 动态代理;
  • 没有接口时,使用 CGLIB 类代理。

Spring Boot 的 AOP 自动配置默认倾向使用 CGLIB 类代理。可以通过以下配置切换为 JDK 代理:

properties 复制代码
spring.aop.proxy-target-class=false

面试时,应区分"Spring 支持哪两类代理"和"Spring Boot 默认使用哪一类代理"。

7. 为什么自调用无法被增强

text 复制代码
调用者
  ↓
proxy.foo()
  ↓
Advice
  ↓
target.foo()
  ↓
this.bar()

调用已经进入 target.foo() 后,this 指向目标对象,不是代理对象。

因此,this.bar() 不会重新经过代理,bar() 上的事务、缓存、异步或自定义切面都可能无法触发。


七、@Transactional 原理

1. 注解本身只是事务元数据

@Transactional 不负责直接操作数据库事务,它只是告诉 Spring:这个方法需要什么样的事务语义。

真正执行事务逻辑的是:

  • AOP 代理;
  • TransactionInterceptor
  • PlatformTransactionManager 的具体实现。

典型执行过程如下:

text 复制代码
调用事务代理
      ↓
读取 @Transactional 属性
      ↓
开启新事务或加入已有事务
      ↓
调用目标业务方法
      ↓
正常返回:提交
符合规则的异常:回滚
      ↓
释放并解绑事务资源

2. 默认事务行为

@Transactional 不写参数时,常见默认值包括:

  • 传播行为:REQUIRED
  • 隔离级别:使用底层数据库或数据源默认值;
  • 事务类型:读写事务;
  • 超时时间:使用底层事务系统默认值;
  • RuntimeExceptionError 默认回滚;
  • 受检异常默认不回滚。

readOnly = true 通常是一种优化提示,不应该简单理解成所有数据库环境都会强制禁止写入。

3. 高频事务传播行为

REQUIRED

默认传播行为。有事务就加入,没有事务就创建。

如果内部事务逻辑把公共事务标记成 rollback-only,外层即使捕获异常并尝试提交,也可能收到 UnexpectedRollbackException

REQUIRES_NEW

挂起外部事务,创建独立物理事务。内外事务可以分别提交或回滚。

它通常还会申请新的数据库连接。如果大量并发线程都持有外层事务连接,又等待内部事务获取新连接,可能耗尽连接池。

NESTED

通常基于同一个物理事务的 savepoint 实现局部回滚,主要适用于支持 JDBC 保存点的事务管理器。

它与 REQUIRES_NEW 不同:前者通常共享物理事务,后者使用独立物理事务。

其他传播行为
  • SUPPORTS:有事务就加入,没有也可以执行;
  • NOT_SUPPORTED:以非事务方式运行,并挂起已有事务;
  • MANDATORY:必须已经存在事务;
  • NEVER:必须不存在事务。

八、事务失效的常见场景

事务失效问题看似很多,本质上主要检查两点:

  1. 调用有没有经过代理;
  2. 异常有没有满足回滚规则。

1. 同类方法内部调用

java 复制代码
@Service
public class OrderService {

    public void create() {
        save();
    }

    @Transactional
    public void save() {
        // database operations
    }
}

create() 内部调用 save(),本质是:

java 复制代码
this.save();

调用没有经过事务代理,所以 save() 上的事务不会被拦截。

推荐的处理方式,是将事务方法拆分到另一个 Spring Bean 中,通过 Bean 间调用进入代理。

2. 对象不是 Spring Bean

java 复制代码
OrderService service = new OrderService();

自己 new 出来的对象没有被 Spring 管理,也没有 AOP 代理,@Transactional 不会生效。

3. 方法无法被代理

更准确的回答是:

  • JDK 代理只能代理接口暴露的方法;
  • CGLIB 无法增强 final 类和 final 方法;
  • private 方法无法被常规类代理重写;
  • Spring Framework 6 的类代理在特定情况下可以支持 protected 或包可见事务方法;
  • 工程上仍建议将事务放在具体类的 public 业务方法上。

"事务只能放在 public 方法上"是偏旧、偏保守的面经结论,不适合不加版本前提地绝对化表达。

4. 异常被业务代码吞掉

java 复制代码
@Transactional
public void createOrder() {
    try {
        repository.save();
    } catch (Exception e) {
        log.warn("save failed", e);
    }
}

异常没有抛出事务代理边界,事务拦截器看到的是正常返回,默认就会尝试提交。

5. 受检异常默认不回滚

例如方法抛出 IOException,默认可能不会回滚。需要根据业务要求配置:

java 复制代码
@Transactional(rollbackFor = Exception.class)

但不建议不分场景地给所有方法都添加 rollbackFor = Exception.class,应结合业务异常体系设计回滚规则。

6. 跨线程调用

传统命令式事务通常通过 ThreadLocal 将事务资源绑定到当前线程。

如果业务执行过程中:

  • 手动创建新线程;
  • 使用线程池;
  • 切换到 @Async 方法;

原线程事务不会自动传播到新线程。异步任务应该在新线程入口重新定义事务边界。

7. 使用了错误的事务管理器

多数据源系统中,如果方法选择的 TransactionManager 与实际访问的数据源不匹配,就会表现出"事务没有生效"。

还需要检查:

  • 所有操作是否使用同一个数据源;
  • 是否确实加入同一个事务;
  • 数据库和表的存储引擎是否支持事务。

8. 在初始化阶段调用事务方法

不要依赖 @PostConstruct 中的事务调用。此时 Bean 仍处于初始化阶段,事务代理不一定已经成为当前调用入口。

9. 把数据库事务误认为分布式事务

本地数据库事务不能回滚已经完成的:

  • HTTP 调用;
  • 消息发送;
  • 文件写入;
  • 其他系统中的数据修改。

跨系统一致性通常需要 outbox、可靠消息、幂等和补偿机制,而不是仅仅添加一个 @Transactional


九、把所有知识点串成一道综合面试题

问题

一个带有 @Transactional 的 Service,是如何被 Controller 调用并最终提交事务的?

参考回答

应用从 SpringApplication.run() 启动。Spring Boot 先准备 Environment,再创建 ApplicationContext,并在 refresh() 阶段解析主配置、组件扫描和自动配置,注册 BeanDefinition。

随后,IOC 容器实例化 Controller、Service 和 Repository,通过 DI 完成对象组装。Service 初始化过程中,自动代理创建器发现它匹配事务 Advisor,于是为它创建 AOP 代理。Controller 最终注入到的通常是这个代理对象。

Web Server 启动后,请求先经过 Filter,再进入 DispatcherServletHandlerMapping 找到 Controller,HandlerAdapter 完成参数解析并调用 Controller。

Controller 调用 Service 时,调用首先进入事务代理。TransactionInterceptor 读取 @Transactional 属性,通过事务管理器开启事务或加入已有事务,然后调用目标 Service。业务方法正常返回就提交,抛出符合回滚规则的异常就回滚。

如果 Service 内部通过 this 调用同类事务方法,调用不会再次经过代理,因此该方法上的事务增强可能失效。

这段回答把以下知识点全部串了起来:

  • Spring Boot 启动;
  • 自动配置;
  • IOC/DI;
  • Bean 生命周期;
  • Spring MVC;
  • AOP;
  • 动态代理;
  • @Transactional
  • 事务失效。

十、高频面试题速答

1. Spring Boot 和 Spring Framework 是什么关系

Spring Framework 提供 IOC、AOP、事务、MVC 等核心能力;Spring Boot 通过 starter、自动配置、内嵌服务器和约定优于配置,降低 Spring 应用的搭建成本。

Spring Boot 没有替代 Spring Framework,而是组织并自动配置它。

2. @Autowired 是如何生效的

Spring 注册负责处理注解的 BeanPostProcessor。Bean 创建过程中,处理器解析构造器、字段或方法上的注入点,再按照类型、@Primary@Qualifier 等规则选择候选 Bean 并注入。

3. @Transactional 是 AOP 吗

声明式事务通常通过 Spring AOP 代理实现。注解只是事务元数据,真正开启、提交和回滚事务的是事务拦截器和事务管理器。

4. Bean 和普通 Java 对象有什么区别

Bean 本质上仍然是 Java 对象,但它的创建、配置、依赖注入、初始化、销毁和代理增强由 Spring 容器负责。

脱离容器自己 new 出来的同类对象,不会自动获得这些能力。

5. 为什么事务方法建议放在 Service 层

事务边界通常应该包围一个完整业务用例。Service 层负责组织多个 Repository 操作,更适合定义业务事务边界。

如果把事务零散地放在 Repository 层,多个数据库操作可能无法自然组成一个整体事务。

6. 事务没有回滚应该怎么排查

可以沿着四条线检查:

  1. 调用是否经过 Spring 代理;
  2. 异常是否抛出了代理边界;
  3. 异常是否符合回滚规则;
  4. 所有数据操作是否加入同一个事务。

十一、面试表达建议

回答 Spring 原理题时,可以采用以下结构:

text 复制代码
一句话结论
    ↓
核心执行流程
    ↓
关键扩展点或源码入口
    ↓
容易失效的边界条件

例如回答事务原理:

  1. 先说事务基于 AOP 代理;
  2. 再说 TransactionInterceptor 和事务管理器的执行流程;
  3. 接着说默认传播行为与回滚规则;
  4. 最后补充自调用、异常吞掉和跨线程问题。

比起背很多类名,面试官更关心你能否解释:

  • Bean 什么时候进入容器;
  • 依赖什么时候注入;
  • 代理什么时候生成;
  • 调用有没有经过代理;
  • 事务边界究竟在哪里。

十二、总结

本文的九个知识点可以浓缩为一句话:

Spring Boot 启动并刷新 Spring 容器,自动配置和组件扫描注册 BeanDefinition;IOC 容器创建并组装 Bean,BeanPostProcessor 为匹配的对象生成 AOP 代理;Spring MVC 把请求分发到 Controller,Controller 通过代理调用 Service,事务拦截器在业务方法前后完成事务管理。

最后再记住三个判断原则:

  1. IOC 的核心是对象控制权交给容器;
  2. AOP 的核心是调用经过代理和拦截器链;
  3. 事务排查的核心是代理边界、线程边界和异常边界。

理解这条主线之后,启动流程、自动配置、Bean 生命周期、MVC 和事务就不再是互不相关的面试题,而是一套完整的运行机制。


参考资料

相关推荐
神秘的猪头1 小时前
Gin 项目为什么要分 Handler、Service、Repository?顺便讲透接口、依赖注入与指针
后端·go
程序员cxuan1 小时前
DeepSeek V4.1 Flash 正式发布!
人工智能·后端·程序员
特立独行的猫A1 小时前
AtomMQTT Broker — 用 Rust 实现的轻量级高性能 MQTT 消息代理
前端·后端·架构
the局外人1 小时前
学习 FastAPI 的 Day 3:企业级目录与数据库迁移
后端·python·fastapi
mldong1 小时前
AI Agent 不能自己签字:用 Python 工作流引擎给 AI 加一道人类审批闸门
后端·python·agent
她的男孩1 小时前
多租户隔离怎么落地?拆完这1600行Starter源码,我把5个坑全踩明白了
java·后端·架构
宫水三叶的刷题日记1 小时前
铁打的影视飓风,流水的新 iPhone
后端
Bs_MoneyMagnet1 小时前
基于springboot+vue的医院陪诊服务预约平台的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring
SimonKing1 小时前
一个Docker命令,40万首古诗词API开箱即用
java·后端·程序员