Spring Bean 生命周期详解——从出生到销毁,结合源码全程追踪

目录

  • [1. 什么是 Bean 的生命周期?](#1. 什么是 Bean 的生命周期?)
  • [2. 生命周期全景图](#2. 生命周期全景图)
  • [3. 第一阶段:实例化(Instantiation)](#3. 第一阶段:实例化(Instantiation))
  • [4. 第二阶段:属性填充(Population)](#4. 第二阶段:属性填充(Population))
  • [5. 第三阶段:初始化(Initialization)](#5. 第三阶段:初始化(Initialization))
  • [6. 第四阶段:使用(In Use)](#6. 第四阶段:使用(In Use))
  • [7. 第五阶段:销毁(Destruction)](#7. 第五阶段:销毁(Destruction))
  • [8. 源码追踪:从 refresh() 到 Bean 诞生](#8. 源码追踪:从 refresh() 到 Bean 诞生)
  • [9. 实战演示:亲眼看到每个回调的执行顺序](#9. 实战演示:亲眼看到每个回调的执行顺序)
  • [10. BeanPostProcessor------Spring 最强大的扩展点](#10. BeanPostProcessor——Spring 最强大的扩展点)
  • [11. 面试题精选与回答思路](#11. 面试题精选与回答思路)
  • [12. 总结](#12. 总结)

1. 什么是 Bean 的生命周期?

先从生活说起

每个人都有生命周期:出生 → 成长 → 工作 → 退休

Spring 中的 Bean 也一样,它不是凭空出现在容器中的,而是经历了一系列明确的阶段:

复制代码
Bean 的一生:
  出生(实例化)→ 打疫苗/上学(属性填充 + 初始化)→ 上班干活(使用)→ 退休(销毁)

官方定义

Spring 官方文档对 Bean 生命周期的描述:

The Spring IoC container manages the lifecycle of beans. The container creates and manages beans according to the configuration metadata. Spring provides several mechanisms for you to interact with the bean lifecycle management.

--- Spring Framework 官方文档 - Lifecycle Callbacks

翻译:Spring IoC 容器管理 Bean 的生命周期。容器根据配置元数据来创建和管理 Bean。Spring 提供了多种机制让你介入 Bean 的生命周期管理。

通俗理解 :Bean 的生命周期就是 Spring 容器创建 Bean、配置 Bean、使用 Bean、销毁 Bean 的完整过程。在这个过程的各个节点上,Spring 提供了"钩子"(回调方法),让你可以在特定时机执行自定义逻辑。


2. 生命周期全景图

先看全貌,再逐一深入:

复制代码
┌──────────────────────────────────────────────────────────────┐
│                    Spring Bean 生命周期                        │
│                                                              │
│  ┌─────────────┐                                             │
│  │ 第一阶段     │  实例化(Instantiation)                      │
│  │ "出生"       │  → 调用构造方法,创建对象                      │
│  └──────┬──────┘                                             │
│         ▼                                                    │
│  ┌─────────────┐                                             │
│  │ 第二阶段     │  属性填充(Population)                       │
│  │ "打疫苗"     │  → @Autowired 注入依赖                       │
│  └──────┬──────┘                                             │
│         ▼                                                    │
│  ┌─────────────┐                                             │
│  │ 第三阶段     │  初始化(Initialization)                     │
│  │ "岗前培训"   │  → Aware 回调 → @PostConstruct → afterPropertiesSet → init-method │
│  └──────┬──────┘                                             │
│         ▼                                                    │
│  ┌─────────────┐                                             │
│  │ 第四阶段     │  使用(In Use)                               │
│  │ "上班干活"   │  → Bean 在容器中被正常使用                     │
│  └──────┬──────┘                                             │
│         ▼                                                    │
│  ┌─────────────┐                                             │
│  │ 第五阶段     │  销毁(Destruction)                          │
│  │ "退休"       │  → @PreDestroy → destroy() → destroy-method │
│  └─────────────┘                                             │
└──────────────────────────────────────────────────────────────┘

每个阶段内部还有更细的步骤,接下来逐一讲解。


3. 第一阶段:实例化(Instantiation)

做了什么?

Spring 通过调用构造方法 来创建 Bean 的实例。此时对象已经"出生"了,但它的字段还没有被赋值(还是 null)。

生活比喻

婴儿刚出生------人是出来了,但什么都不会,什么都没有。

对应的源码

Spring 中负责实例化 Bean 的核心方法在 AbstractAutowireCapableBeanFactory 类中:

java 复制代码
// AbstractAutowireCapableBeanFactory.java(简化版)
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
    
    // ▶ 第一步:实例化 --- 调用构造方法创建对象
    BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
    Object bean = instanceWrapper.getWrappedInstance();
    
    // ▶ 第二步:属性填充(下一节讲)
    populateBean(beanName, mbd, instanceWrapper);
    
    // ▶ 第三步:初始化(再下一节讲)
    exposedObject = initializeBean(beanName, exposedObject, mbd);
    
    return exposedObject;
}

createBeanInstance() 方法内部会决定用哪个构造方法来创建对象:

java 复制代码
// AbstractAutowireCapableBeanFactory.java(简化版)
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
    // 1. 如果有工厂方法(@Bean 方法),用工厂方法创建
    if (mbd.getFactoryMethodName() != null) {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }
    
    // 2. 如果有带参构造方法,用带参构造方法创建(构造器注入)
    // 3. 否则用无参构造方法创建
    return instantiateBean(beanName, mbd);
}

关键点

  • 实例化之后,对象已经在内存中了
  • @Autowired 的字段此时还是 null(还没注入)
  • 如果构造方法有参数(构造器注入),Spring 会在这一步就把依赖找到并传入

4. 第二阶段:属性填充(Population)

做了什么?

Spring 把 Bean 依赖的其他对象(通过 @Autowired@Value@Resource 等标注的字段)注入进来。

生活比喻

婴儿出生后,护士给他打疫苗、穿衣服、戴手环------把需要的东西一样一样地"装"上去。

对应的源码

java 复制代码
// AbstractAutowireCapableBeanFactory.java(简化版)
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
    
    // 1. 获取所有 BeanPostProcessor,找到处理注入的那些
    for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorsCache().instantiationAware) {
        // 2. AutowiredAnnotationBeanPostProcessor 在这里处理 @Autowired 和 @Value
        // 3. CommonAnnotationBeanPostProcessor 在这里处理 @Resource
        PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
    }
    
    // 4. 将属性值真正设置到 Bean 的字段上
    applyPropertyValues(beanName, mbd, bw, pvs);
}

实际处理 @Autowired 注入的是 AutowiredAnnotationBeanPostProcessor

java 复制代码
// AutowiredAnnotationBeanPostProcessor.java(简化版)
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    // 1. 找到 bean 中所有标了 @Autowired 的字段和方法
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    // 2. 逐个注入
    metadata.inject(bean, beanName, pvs);
    return pvs;
}

关键点

  • 属性填充完成后,Bean 的所有依赖都已经就位
  • @Autowired 的底层就是通过 AutowiredAnnotationBeanPostProcessor 在这个阶段完成的
  • @Resource 则是通过 CommonAnnotationBeanPostProcessor 处理的

5. 第三阶段:初始化(Initialization)

这是生命周期中步骤最多、最复杂的阶段,也是面试中问得最细的部分。

做了什么?

依赖注入完成后,Spring 会依次调用一系列"回调方法",让 Bean 有机会做一些自定义的初始化操作

生活比喻

小孩长大了,开始上学:先告诉他"你叫什么名字"(Aware 回调),然后参加岗前培训(初始化方法),最后正式上岗。

初始化阶段的完整执行顺序

复制代码
属性填充完成
    ↓
① Aware 接口回调
    → BeanNameAware.setBeanName()           "告诉你,你在容器中叫什么名字"
    → BeanFactoryAware.setBeanFactory()     "告诉你,你在哪个工厂里"
    → ApplicationContextAware.setApplicationContext()  "告诉你,你在哪个容器里"
    ↓
② BeanPostProcessor.postProcessBeforeInitialization()
    → 所有 BeanPostProcessor 的"前置处理"
    → @PostConstruct 就是在这一步被调用的!
    ↓
③ InitializingBean.afterPropertiesSet()
    → 如果 Bean 实现了 InitializingBean 接口
    ↓
④ 自定义 init-method
    → @Bean(initMethod = "init") 指定的方法
    ↓
⑤ BeanPostProcessor.postProcessAfterInitialization()
    → 所有 BeanPostProcessor 的"后置处理"
    → AOP 代理就是在这一步创建的!
    ↓
Bean 初始化完成,可以使用了

对应的源码

java 复制代码
// AbstractAutowireCapableBeanFactory.java(简化版)
protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
    
    // ① Aware 回调
    invokeAwareMethods(beanName, bean);
    
    // ② BeanPostProcessor 前置处理(@PostConstruct 在这里执行)
    Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    
    // ③ + ④ InitializingBean.afterPropertiesSet() + 自定义 init-method
    invokeInitMethods(beanName, wrappedBean, mbd);
    
    // ⑤ BeanPostProcessor 后置处理(AOP 代理在这里创建)
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    
    return wrappedBean;
}

我们来逐一看每个步骤的源码。

① Aware 回调
java 复制代码
// AbstractAutowireCapableBeanFactory.java
private void invokeAwareMethods(String beanName, Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof BeanNameAware beanNameAware) {
            beanNameAware.setBeanName(beanName);           // 告诉 Bean "你叫什么名字"
        }
        if (bean instanceof BeanClassLoaderAware classLoaderAware) {
            classLoaderAware.setBeanClassLoader(classLoader);  // 告诉 Bean "类加载器是哪个"
        }
        if (bean instanceof BeanFactoryAware beanFactoryAware) {
            beanFactoryAware.setBeanFactory(beanFactory);   // 告诉 Bean "你在哪个工厂里"
        }
    }
}

什么时候需要实现 Aware 接口? 当你的 Bean 需要获取 Spring 容器本身的一些信息时。比如你想在 Bean 内部获取 ApplicationContext

java 复制代码
@Component
public class MyBean implements ApplicationContextAware {
    private ApplicationContext context;
    
    @Override
    public void setApplicationContext(ApplicationContext context) {
        this.context = context;  // Spring 自动调用这个方法,把容器引用传给你
    }
}
② BeanPostProcessor 前置处理
java 复制代码
// AbstractAutowireCapableBeanFactory.java
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) {
    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        Object current = processor.postProcessBeforeInitialization(result, beanName);
        if (current == null) return result;
        result = current;
    }
    return result;
}

这一步会遍历容器中所有的 BeanPostProcessor,依次调用它们的 postProcessBeforeInitialization() 方法。

@PostConstruct 就是在这一步被处理的。 负责处理它的是 CommonAnnotationBeanPostProcessor(实现了 BeanPostProcessor 接口),它在 postProcessBeforeInitialization() 中扫描 Bean 的方法,找到标了 @PostConstruct 的方法并调用。

③ InitializingBean.afterPropertiesSet()
java 复制代码
// AbstractAutowireCapableBeanFactory.java
protected void invokeInitMethods(String beanName, Object bean, RootBeanDefinition mbd) {
    
    // ③ 如果 Bean 实现了 InitializingBean 接口,调用 afterPropertiesSet()
    if (bean instanceof InitializingBean initializingBean) {
        initializingBean.afterPropertiesSet();
    }
    
    // ④ 如果配置了自定义 init-method,通过反射调用它
    String initMethodName = mbd.getInitMethodName();
    if (initMethodName != null) {
        invokeCustomInitMethod(beanName, bean, mbd);
    }
}
⑤ BeanPostProcessor 后置处理
java 复制代码
// AbstractAutowireCapableBeanFactory.java
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) {
    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        Object current = processor.postProcessAfterInitialization(result, beanName);
        if (current == null) return result;
        result = current;
    }
    return result;
}

AOP 代理就是在这一步创建的。 AnnotationAwareAspectJAutoProxyCreator(也是一个 BeanPostProcessor)在 postProcessAfterInitialization() 中检查 Bean 是否需要被代理,如果需要,就创建代理对象并返回。这就是为什么你 @Autowired 注入的 Bean 实际上可能是代理对象而不是原始对象。

三种初始化方式的执行顺序

如果你同时使用了三种初始化方式,它们的执行顺序是固定的:

复制代码
@PostConstruct 方法        ← 最先执行(在 BeanPostProcessor 前置处理阶段)
    ↓
InitializingBean.afterPropertiesSet()  ← 第二个执行
    ↓
自定义 init-method          ← 最后执行

6. 第四阶段:使用(In Use)

做了什么?

初始化完成后,Bean 就"上岗"了------它待在 Spring 容器中,等着被其他 Bean 使用。

java 复制代码
@RestController
public class UserController {
    @Autowired
    private UserService userService;  // ← 这里拿到的就是已经完成所有生命周期的 Bean
    
    @GetMapping("/users/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.findById(id);  // 正常使用
    }
}

关键点

  • 对于 singleton 作用域的 Bean(默认),它会一直待在容器中,直到容器关闭
  • 对于 prototype 作用域的 Bean,Spring 创建完就"不管了"------不会调用销毁方法

7. 第五阶段:销毁(Destruction)

做了什么?

当 Spring 容器关闭时(比如应用停止),Spring 会依次调用 Bean 的销毁方法,让 Bean 有机会释放资源(关闭数据库连接、停止线程池等)。

生活比喻

员工退休前,要做交接工作------归还公司电脑、交接客户资料、清理工位。

销毁阶段的执行顺序

复制代码
容器开始关闭
    ↓
① @PreDestroy 标注的方法        ← 最先执行
    ↓
② DisposableBean.destroy()      ← 第二个执行
    ↓
③ 自定义 destroy-method          ← 最后执行
    ↓
Bean 被销毁

对应的源码

java 复制代码
// DisposableBeanAdapter.java(简化版)
public void destroy() {
    // ① @PreDestroy(通过 CommonAnnotationBeanPostProcessor 的 DestructionAwareBeanPostProcessor)
    for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
        processor.postProcessBeforeDestruction(this.bean, this.beanName);
    }
    
    // ② DisposableBean.destroy()
    if (this.invokeDisposableBean) {
        ((DisposableBean) this.bean).destroy();
    }
    
    // ③ 自定义 destroy-method
    if (this.destroyMethodName != null) {
        invokeCustomDestroyMethod(this.destroyMethod);
    }
}

常见用途

java 复制代码
@Component
public class ConnectionPool implements DisposableBean {
    
    @PreDestroy
    public void cleanup() {
        System.out.println("@PreDestroy: 开始清理连接池...");
    }
    
    @Override
    public void destroy() {
        System.out.println("DisposableBean: 关闭所有数据库连接");
    }
}

关键点

  • 只有 singleton 的 Bean 才会被 Spring 调用销毁方法
  • prototype 的 Bean,Spring 创建后就不管了,不会调用销毁方法
  • 销毁方法的典型用途:关闭连接池、释放文件句柄、停止后台线程

8. 源码追踪:从 refresh() 到 Bean 诞生

现在我们来从更高的层面看------Spring 容器启动时,Bean 是在哪一步被创建的?

起点:AbstractApplicationContext.refresh()

这是 Spring 容器启动的总入口,也是一个经典的模板方法(参见我们的设计模式博客):

java 复制代码
// AbstractApplicationContext.java(简化版)
public void refresh() {
    // 1. 准备刷新
    prepareRefresh();
    
    // 2. 获取 BeanFactory
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
    // 3. 准备 BeanFactory
    prepareBeanFactory(beanFactory);
    
    // 4. 后处理 BeanFactory(子类扩展点)
    postProcessBeanFactory(beanFactory);
    
    // 5. 执行 BeanFactoryPostProcessor
    invokeBeanFactoryPostProcessors(beanFactory);
    
    // 6. 注册 BeanPostProcessor(重要!为后面的生命周期回调做准备)
    registerBeanPostProcessors(beanFactory);
    
    // 7-10. 初始化消息源、事件广播器、注册监听器等...
    
    // 11. ★ 实例化所有非懒加载的 singleton Bean ★
    finishBeanFactoryInitialization(beanFactory);
    
    // 12. 完成刷新
    finishRefresh();
}

Bean 的创建发生在第 11 步 finishBeanFactoryInitialization()

追踪调用链

复制代码
refresh()
  → finishBeanFactoryInitialization(beanFactory)
    → beanFactory.preInstantiateSingletons()
      → getBean(beanName)
        → doGetBean(beanName)
          → createBean(beanName, mbd, args)
            → doCreateBean(beanName, mbd, args)    ← 这就是我们在第3节看到的方法!
              → createBeanInstance()                 ← 第一阶段:实例化
              → populateBean()                       ← 第二阶段:属性填充
              → initializeBean()                     ← 第三阶段:初始化

在 IDEA 中调试验证

你可以在以下方法上设置断点,启动 Spring Boot 应用后观察调用栈:

断点位置 对应阶段
AbstractAutowireCapableBeanFactory.createBeanInstance() 实例化
AbstractAutowireCapableBeanFactory.populateBean() 属性填充
AbstractAutowireCapableBeanFactory.initializeBean() 初始化
AbstractAutowireCapableBeanFactory.invokeAwareMethods() Aware 回调
CommonAnnotationBeanPostProcessor.postProcessBeforeInitialization() @PostConstruct
InitializingBean.afterPropertiesSet() afterPropertiesSet

在调试器的 Frames(栈帧) 窗口中,你能看到从 refresh() 一路调用到当前方法的完整链路。这就是源码阅读博客中提到的"调用栈就是自动生成的执行流程图"。


9. 实战演示:亲眼看到每个回调的执行顺序

写一个 Demo 类,同时实现所有生命周期回调接口,看看它们的执行顺序:

java 复制代码
@Component
public class LifecycleDemo implements BeanNameAware, BeanFactoryAware, 
        ApplicationContextAware, InitializingBean, DisposableBean {

    private String beanName;

    public LifecycleDemo() {
        System.out.println("1. 【构造方法】调用构造方法,实例化 Bean");
    }

    // ========== 属性填充 ==========
    @Autowired
    public void setDependency(SomeService someService) {
        System.out.println("2. 【属性填充】@Autowired 注入依赖");
    }

    // ========== Aware 回调 ==========
    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("3. 【BeanNameAware】setBeanName() → 我的名字是: " + name);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        System.out.println("4. 【BeanFactoryAware】setBeanFactory()");
    }

    @Override
    public void setApplicationContext(ApplicationContext ctx) {
        System.out.println("5. 【ApplicationContextAware】setApplicationContext()");
    }

    // ========== 初始化 ==========
    @PostConstruct
    public void postConstruct() {
        System.out.println("6. 【@PostConstruct】执行初始化方法");
    }

    @Override
    public void afterPropertiesSet() {
        System.out.println("7. 【InitializingBean】afterPropertiesSet()");
    }

    // 如果配了 @Bean(initMethod = "customInit"),这个方法会在 afterPropertiesSet 之后调用
    public void customInit() {
        System.out.println("8. 【自定义 init-method】customInit()");
    }

    // ========== 销毁 ==========
    @PreDestroy
    public void preDestroy() {
        System.out.println("9. 【@PreDestroy】执行销毁前方法");
    }

    @Override
    public void destroy() {
        System.out.println("10.【DisposableBean】destroy()");
    }

    // 如果配了 @Bean(destroyMethod = "customDestroy"),这个方法会在 destroy 之后调用
    public void customDestroy() {
        System.out.println("11.【自定义 destroy-method】customDestroy()");
    }
}

控制台输出

启动应用后,你会在控制台看到以下输出(按顺序):

复制代码
1. 【构造方法】调用构造方法,实例化 Bean
2. 【属性填充】@Autowired 注入依赖
3. 【BeanNameAware】setBeanName() → 我的名字是: lifecycleDemo
4. 【BeanFactoryAware】setBeanFactory()
5. 【ApplicationContextAware】setApplicationContext()
6. 【@PostConstruct】执行初始化方法
7. 【InitializingBean】afterPropertiesSet()

关闭应用时:

复制代码
9. 【@PreDestroy】执行销毁前方法
10.【DisposableBean】destroy()

记忆口诀

复制代码
构造 → 注入 → Aware → @PostConstruct → afterPropertiesSet → init-method
                               (使用阶段)
@PreDestroy → destroy() → destroy-method

简化记忆:"生(构造)→ 注(注入)→ 知(Aware)→ 前(PostConstruct)→ 后(afterPropertiesSet)→ 用 → 预(PreDestroy)→ 销(destroy)"


10. BeanPostProcessor------Spring 最强大的扩展点

为什么单独讲它?

在 Bean 生命周期中,BeanPostProcessor 是一个非常特殊的存在 ------它不是作用于单个 Bean 的,而是作用于容器中所有 Bean 的。Spring 自身的很多核心功能(@Autowired 注入、@PostConstruct 调用、AOP 代理创建)都是通过 BeanPostProcessor 实现的。

接口定义

java 复制代码
public interface BeanPostProcessor {
    
    // 在初始化之前调用(在 @PostConstruct 之前的一个时机点)
    default Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;
    }
    
    // 在初始化之后调用(AOP 代理在这里创建)
    default Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }
}

它的执行时机

复制代码
属性填充完成
    ↓
Aware 回调
    ↓
★ BeanPostProcessor.postProcessBeforeInitialization() ★  ← 所有 BPP 的前置方法
    ↓
InitializingBean.afterPropertiesSet()
    ↓
自定义 init-method
    ↓
★ BeanPostProcessor.postProcessAfterInitialization() ★   ← 所有 BPP 的后置方法

每个 Bean 在初始化阶段,都会经过所有 BeanPostProcessor 的"过手"。

Spring 内置的重要 BeanPostProcessor

BeanPostProcessor 职责
AutowiredAnnotationBeanPostProcessor 处理 @Autowired@Value 注入
CommonAnnotationBeanPostProcessor 处理 @Resource@PostConstruct@PreDestroy
AnnotationAwareAspectJAutoProxyCreator 创建 AOP 代理对象
ApplicationContextAwareProcessor 处理 ApplicationContextAware 等回调

自定义 BeanPostProcessor 示例

java 复制代码
@Component
public class TimingBeanPostProcessor implements BeanPostProcessor {
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("【BPP 前置】正在初始化: " + beanName);
        return bean;  // 必须返回 bean,否则后续流程拿不到对象
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("【BPP 后置】初始化完成: " + beanName);
        return bean;  // 你也可以返回一个代理对象来替换原始 Bean
    }
}

关键理解

BeanPostProcessor 是 Spring 实现各种"魔法"的核心机制。 理解了它,你就理解了:

  • 为什么 @Autowired 能自动注入(因为有 AutowiredAnnotationBeanPostProcessor
  • 为什么 @PostConstruct 能被调用(因为有 CommonAnnotationBeanPostProcessor
  • 为什么加了 @Transactional 的类会变成代理(因为有 AnnotationAwareAspectJAutoProxyCreator

11. 面试题精选与回答思路

题目一:请描述 Spring Bean 的生命周期

回答思路(分阶段回答,条理清晰):

Spring Bean 的生命周期可以分为五个大阶段:

  1. 实例化:Spring 通过构造方法(或工厂方法)创建 Bean 实例
  2. 属性填充 :通过 @Autowired@Resource 等注解注入依赖
  3. 初始化 :依次执行 Aware 回调 → @PostConstructafterPropertiesSet() → 自定义 init-method。在初始化前后,BeanPostProcessor 会介入处理
  4. 使用:Bean 在容器中被正常使用
  5. 销毁 :容器关闭时,依次执行 @PreDestroydestroy() → 自定义 destroy-method

题目二:@PostConstruct、afterPropertiesSet、init-method 的区别和执行顺序?

执行顺序@PostConstructafterPropertiesSet()init-method

区别

  • @PostConstruct:Jakarta 标准注解,通过 BeanPostProcessor 机制实现,最通用
  • afterPropertiesSet():需要实现 InitializingBean 接口,和 Spring 框架耦合
  • init-method:通过 @Bean(initMethod = "xxx") 指定,适合第三方库(不能改源码加注解时)

题目三:BeanPostProcessor 和 BeanFactoryPostProcessor 的区别?

  • BeanPostProcessor:作用于 Bean 实例------在每个 Bean 初始化前后做处理
  • BeanFactoryPostProcessor:作用于 Bean 定义------在所有 Bean 实例化之前,修改 Bean 的配置元数据

比喻:BeanFactoryPostProcessor 修改的是"配方"(还没做菜之前改食谱),BeanPostProcessor 处理的是"成品"(菜做出来之后加调料)。

题目四:Spring 是如何解决循环依赖的?

Spring 使用三级缓存 来解决 singleton Bean 之间通过属性注入(@Autowired)产生的循环依赖:

缓存 名称 存的内容
一级缓存 singletonObjects 完全初始化好的 Bean
二级缓存 earlySingletonObjects 提前曝光的半成品 Bean(已实例化,未初始化)
三级缓存 singletonFactories Bean 的工厂对象(用于创建代理)

核心流程:A 依赖 B,B 依赖 A

  1. 创建 A → 实例化 A → 把 A 的工厂放入三级缓存 → 填充 A 的属性 → 发现需要 B
  2. 创建 B → 实例化 B → 填充 B 的属性 → 发现需要 A → 从三级缓存拿到 A 的早期引用
  3. B 初始化完成 → 回到 A 的属性填充 → A 拿到 B → A 初始化完成

注意 :构造器注入的循环依赖 Spring 无法解决(因为实例化都完不成,没法放入缓存)。


12. 总结

生命周期完整流程(精简版)

复制代码
构造方法(实例化)
    ↓
@Autowired / @Resource(属性填充)
    ↓
BeanNameAware / BeanFactoryAware / ApplicationContextAware(Aware 回调)
    ↓
BeanPostProcessor.postProcessBeforeInitialization()(前置处理)
    ↓
@PostConstruct(注解初始化)
    ↓
InitializingBean.afterPropertiesSet()(接口初始化)
    ↓
init-method(自定义初始化)
    ↓
BeanPostProcessor.postProcessAfterInitialization()(后置处理,AOP 在此创建代理)
    ↓
===== Bean 可以使用了 =====
    ↓
@PreDestroy(注解销毁)
    ↓
DisposableBean.destroy()(接口销毁)
    ↓
destroy-method(自定义销毁)

核心源码对照表

生命周期阶段 对应源码方法 所在类
实例化 createBeanInstance() AbstractAutowireCapableBeanFactory
属性填充 populateBean() AbstractAutowireCapableBeanFactory
Aware 回调 invokeAwareMethods() AbstractAutowireCapableBeanFactory
BPP 前置 applyBeanPostProcessorsBeforeInitialization() AbstractAutowireCapableBeanFactory
初始化方法 invokeInitMethods() AbstractAutowireCapableBeanFactory
BPP 后置 applyBeanPostProcessorsAfterInitialization() AbstractAutowireCapableBeanFactory
销毁 destroy() DisposableBeanAdapter

一句话总结

Bean 的生命周期 = Spring 容器创建、配置、使用、销毁 Bean 的完整过程。核心代码都在 AbstractAutowireCapableBeanFactory.doCreateBean() 方法中------实例化、属性填充、初始化三步走。理解了这个方法,就理解了 Bean 生命周期的 80%。


参考资料

官方文档

相关推荐
怒放吧德德1 小时前
AsyncTool + SpringBoot:轻量级异步编排最佳实践
java·后端
毅炼2 小时前
Java 集合常见问题总结(1)
java·后端
知识即是力量ol2 小时前
口语八股——Spring 面试实战指南(一):核心概念篇、AOP 篇
java·spring·面试·aop·八股·核心概念篇
utmhikari2 小时前
【架构艺术】治理后端稳定性的一些实战经验
java·开发语言·后端·架构·系统架构·稳定性·后端开发
文艺倾年2 小时前
【源码精讲+简历包装】LeetcodeRunner—手搓调试器轮子(20W字-上)
java·jvm·人工智能·tomcat·编辑器·guava
dfyx9992 小时前
Maven Spring框架依赖包
java·spring·maven
undefinedType2 小时前
Rails ActiveSupport::Cache 缓存存储详解
后端
茶杯梦轩3 小时前
从零起步学习并发编程 || 第二章:多线程与死锁在项目中的应用示例
java·服务器·后端
日月云棠3 小时前
JAVA JDK 11 特性详解
java