Skip to content
极高进阶

一句话答案

事务失效常见原因:自调用(未走代理)、方法非 public、异常被 catch 吞掉、rollbackFor 未指定、非 Spring 管理的 Bean。

核心要点

SpringApplication.run() 的完整流程:

SpringApplication.run(MyApp.class, args)


① 创建 SpringApplication 对象
   → 推断应用类型(NONE/SERVLET/REACTIVE)
   → 从 spring.factories 加载 ApplicationContextInitializer
   → 从 spring.factories 加载 ApplicationListener


② run() 方法执行

  ├─ 获取 SpringApplicationRunListeners(从 spring.factories 加载)
  │  发布 ApplicationStartingEvent

  ├─ 准备环境(prepareEnvironment)
  │  → 创建 ConfigurableEnvironment
  │  → 加载配置(application.properties / application.yml)
  │  → 发布 ApplicationEnvironmentPreparedEvent

  ├─ 打印 Banner(Spring Boot 的 ASCII 图案)

  ├─ 创建 ApplicationContext
  │  → 根据应用类型创建 AnnotationConfigServletWebServerApplicationContext
  │  → 或 AnnotationConfigApplicationContext(非 Web)

  ├─ prepareContext(准备上下文)
  │  → 应用 ApplicationContextInitializer
  │  → 注册主配置类(@SpringBootApplication 所在类)
  │  → 发布 ApplicationContextInitializedEvent

  ├─ refreshContext(刷新上下文)← 核心步骤,调用 AbstractApplicationContext.refresh()
  │  → 加载所有 Bean 定义(BeanDefinition)
  │  → 创建并初始化所有单例 Bean(走 Bean 生命周期)
  │  → 启动内嵌 Tomcat(onRefresh 阶段)
  │  → 发布 ContextRefreshedEvent

  ├─ afterRefresh(刷新后)
  │  → 调用所有 ApplicationRunner / CommandLineRunner 的 run() 方法

  └─ 发布 ApplicationStartedEvent
     发布 ApplicationReadyEvent ← 服务完全启动,可对外提供服务

关键:refreshContext() 内部调用 AbstractApplicationContext.refresh(),这 12 步是 Spring 容器启动的核心:

prepareRefresh()            → 初始化环境变量
obtainFreshBeanFactory()    → 创建/刷新 BeanFactory
prepareBeanFactory()        → 注册内置组件(如 Environment)
postProcessBeanFactory()    → 子类扩展
invokeBeanFactoryPostProcessors() → 执行 BeanFactoryPostProcessor(如扫描 @Component)
registerBeanPostProcessors()      → 注册 BeanPostProcessor
initMessageSource()         → 国际化
initApplicationEventMulticaster() → 初始化事件广播器
onRefresh()                 → 子类扩展(Web 容器在这里启动 Tomcat)
registerListeners()         → 注册监听器
finishBeanFactoryInitialization() → 实例化所有非懒加载单例 Bean(核心!)
finishRefresh()             → 发布 ContextRefreshedEvent
追问与易错

追问方向:

  • 自调用为什么事务失效?怎么解决?(未经过代理,解决:注入自己/AopContext/抽方法到另一个类)
  • @Transactional 默认回滚什么异常?(RuntimeException + Error,不回滚 checked Exception)
  • 事务传播行为 REQUIRES_NEW 和 NESTED 的区别?(NEW 独立事务,NESTED 基于保存点)

易错点:

  • ❌ "加了 @Transactional 就有事务"——还要检查代理方式、异常类型、是否自调用
  • ❌ "private 方法加 @Transactional 也有效"——无效,CGLIB 无法代理 private 方法

💡 记忆锚点

事务失效 = 代理没接住:自调用(this绕过代理)、非public(代理拦不到)、异常被catch(Spring不知道出事了)、checked异常(默认只回滚RuntimeException)。记住"事务靠代理,代理靠public方法的外部调用"。