面试知识库
困难

Spring源码追问入口图#

一句话答案#

Spring 源码追问三条主线:Bean 生命周期(实例化→属性注入→初始化→销毁,关键类 BeanFactory/BeanPostProcessor)、AOP 代理生成(AbstractAutoProxyCreator 在 BeanPostProcessor 中织入)、事务拦截器(TransactionInterceptor 通过 AOP 拦截 @Transactional 方法调用 PlatformTransactionManager)。

核心要点

一、Bean 生命周期调用链

核心类速查:

职责
DefaultListableBeanFactoryIoC 容器核心,管理 BeanDefinition 和 Bean 实例
AbstractAutowireCapableBeanFactorycreateBean/doCreateBean 入口
AutowiredAnnotationBeanPostProcessor处理 @Autowired/@Value 注入
CommonAnnotationBeanPostProcessor处理 @PostConstruct/@PreDestroy/@Resource
ConfigurationClassPostProcessor解析 @Configuration 类
AbstractAutoProxyCreatorAOP 代理创建入口

二、AOP 代理生成链路

@EnableAspectJAutoProxy
  → 注册 AnnotationAwareAspectJAutoProxyCreator (是一个 BeanPostProcessor)
    → postProcessAfterInitialization() 中:
      1. getAdvicesAndAdvisorsForBean() 找匹配的切面
      2. 有匹配 → createProxy()
         ├─ 目标类实现了接口 → JDK 动态代理
         └─ 目标类未实现接口 → CGLIB 代理
      3. 返回代理对象替换原始 Bean
plaintext

JDK vs CGLIB 代理:

维度JDK 动态代理CGLIB
条件目标类实现了接口无接口要求
原理Proxy.newProxyInstance + InvocationHandler生成子类 + MethodInterceptor
限制只能代理接口方法不能代理 final 类/方法
Spring Boot 默认2.0 前默认 JDK2.0+ 默认 CGLIB (proxyTargetClass=true)

三、事务拦截器链路

@Transactional 方法被调用
  → CGLIB/JDK 代理拦截
    → TransactionInterceptor.invoke()
      → TransactionAspectSupport.invokeWithinTransaction()
        1. getTransaction() → 从 PlatformTransactionManager 获取/创建事务
           └─ DataSourceTransactionManager → 从 DataSource 获取 Connection
           └─ 设置 autocommit=false
           └─ 绑定 Connection 到 ThreadLocal (TransactionSynchronizationManager)
        2. 执行目标方法
        3. 成功 → commitTransactionAfterReturning() → commit
        4. 异常 → completeTransactionAfterThrowing()
           └─ 检查 rollbackFor/noRollbackFor 配置
           └─ 匹配 → rollback
           └─ 不匹配 → commit(这是事务失效的常见原因!)
plaintext

事务失效场景→源码根因:

场景源码根因
同类方法调用不经过代理,直接 this 调用不触发 TransactionInterceptor
private/final 方法CGLIB 无法生成子类覆盖方法
异常被 catchcompleteTransactionAfterThrowing 没收到异常
抛 checked 异常默认只回滚 RuntimeException/Error
非 Spring 管理的类没有代理对象,不走拦截器

四、循环依赖三级缓存→源码

// DefaultSingletonBeanRegistry 中:
Map<String, Object> singletonObjects;          // 一级:成品 Bean
Map<String, Object> earlySingletonObjects;     // 二级:早期引用(可能是代理)
Map<String, ObjectFactory<?>> singletonFactories; // 三级:创建早期引用的工厂

// getSingleton() 查找顺序:一级 → 二级 → 三级(调用工厂方法后放入二级)
// 三级缓存存工厂而非对象:为了在需要时才决定是否返回代理对象(AOP场景)
java

为什么不能解决构造器注入循环依赖?→ 三级缓存是在实例化后属性注入前放入的,构造器注入时实例都没创建完。

面试回答(2分钟版)

Spring 源码我准备了三条主线。第一条是 Bean 生命周期:从 BeanDefinition 加载开始,经过实例化、属性注入、初始化三个阶段。属性注入由 AutowiredAnnotationBeanPostProcessor 处理 @Autowired,初始化阶段的 postProcessAfterInitialization 是 AOP 代理创建的时机。第二条是 AOP 代理生成:AnnotationAwareAspectJAutoProxyCreator 作为 BeanPostProcessor,在初始化后检查是否有匹配的切面,有就创建代理。Spring Boot 2.0 后默认用 CGLIB 生成子类代理。第三条是事务拦截器:@Transactional 通过 AOP 织入 TransactionInterceptor,调用时先从 DataSourceTransactionManager 获取连接设为非自动提交,绑定到 ThreadLocal,方法成功就 commit,异常就检查 rollbackFor 配置决定是否回滚。这也解释了事务失效场景:同类方法调用不走代理所以不触发拦截器,checked 异常默认不回滚因为只匹配 RuntimeException。循环依赖靠三级缓存解决,三级存的是 ObjectFactory 而非对象,是为了延迟决定是否返回代理。

追问与易错

追问方向:

  • “BeanFactoryPostProcessor 和 BeanPostProcessor 区别?”→ BFPP 在 Bean 实例化之前执行,修改 BeanDefinition 元数据(如 PropertyPlaceholderConfigurer 替换占位符);BPP 在 Bean 初始化前后执行,修改或替换 Bean 实例(如 AOP 代理创建)
  • “为什么三级缓存不能合并成两级?”→ 如果只用两级直接存代理对象,则所有 Bean 都要提前创建代理,违反 AOP 只在需要时(有循环依赖引用时)才创建代理的原则;三级缓存存 ObjectFactory 实现延迟代理创建
  • “@Transactional(propagation=REQUIRES_NEW) 怎么实现的?”→ 挂起当前事务(将当前连接从 ThreadLocal 解绑保存到 SuspendedResourcesHolder)、从连接池获取新连接创建独立事务、执行完独立 commit/rollback、最后恢复挂起的外层事务
  • “Spring Boot 自动配置原理?”→ @EnableAutoConfiguration 通过 AutoConfigurationImportSelector 加载候选配置类(Boot 3 用 AutoConfiguration.imports),@Conditional 系列注解条件过滤,按需注册 Bean

易错点:

  • ❌ “AOP 在属性注入时创建代理”——是在初始化的 postProcessAfterInitialization 中
  • ❌ “三级缓存是为了解决循环依赖”——两级就能解决,三级是为了延迟代理创建
  • ❌ “事务失效是因为没有 @Transactional”——更常见的是同类调用/异常被吞/异常类型不对
  • ✅ 三条主线记清楚:Bean 生命周期(BPP)、AOP(代理创建时机)、事务(拦截器+回滚规则)