Spring Bean 生命周期

一、图解生命周期 4 大阶段

【Spring Bean 生命周期 - 4 大阶段】

阶段 1:Bean 定义(BeanDefinition)

阶段 2:实例化(构造方法 / 工厂方法)

阶段 3:初始化赋值(依赖注入 → Aware 接口 → BeanPostProcessor → 初始化方法)

阶段 4:销毁 bean

Bean 的创建和初始化赋值是分开的"------这是核心,**很多老开发都搞混"实例化"和"初始化"。

二、阶段 1:Bean 定义(BeanDefinition)

2.1 触发时机

Spring 启动时 (不是 @Autowired 时!),Spring 扫描所有 @Component / @Service / @Controller / @Repository / @Bean为每个类生成一个 BeanDefinition

2.2 BeanDefinition 包含什么
复制代码
public class BeanDefinition {    private String beanClassName;       // 类全限定名    private String factoryBeanName;     // 工厂 Bean 名(@Configuration 用)    private String factoryMethodName;   // 工厂方法名    private String scope;                // singleton / prototype    private boolean lazyInit;           // 是否懒加载    private String initMethodName;      // 初始化方法    private String destroyMethodName;   // 销毁方法    private ConstructorArgumentValues constructorArgumentValues;  // 构造参数    private MutablePropertyValues propertyValues;              // 属性值    // ... 还有很多}
2.3 项目对应

@Service // ✅ Spring 启动时扫描到这个注解,生成 BeanDefinition

public class PerformanceService {

// ...

}

三、阶段 2:实例化(Instantiation)

3.1 触发时机

第一次 getBean() 时(singleton 在容器启动时实例化,prototype 在 getBean 时实例化)。

3.2 实例化做了什么

调用构造方法创建对象但还没赋值!):

@Service

public class UserService {

@Autowired // ⚠️ 此时还没注入!

private UserDao userDao;

public UserService() { // ✅ 构造方法被调用

System.out.println("实例化:userDao = " + userDao); // null

}

}

输出:

实例化:userDao = null // ⚠️ 此时 userDao 还是 null

3.3 4 种实例化方式
方式 例子
默认构造方法 new UserService()
有参构造方法 new UserService("name", 18)
静态工厂方法 UserService.create()
实例工厂方法 factoryBean.createUserService()

Spring 选择顺序: @Autowired 构造方法 > 默认构造方法 > 静态工厂 > 实例工厂

3.4 项目对应

@Component

public class BusinessConsumer {

@Autowired

private StringRedisTemplate redisTemplate; // 阶段 3 才注入

public BusinessConsumer() {

// 阶段 2:实例化(redisTemplate 还是 null)

}

}

四、阶段 3:初始化赋值(核心阶段

4.1 5 个小步骤(按顺序!
  1. 依赖注入(@Autowired / @Resource / @Value)

  1. Aware 接口回调(BeanNameAware / BeanFactoryAware / ApplicationContextAware)

  1. BeanPostProcessor#before(前置处理)

  1. 初始化方法(@PostConstruct / InitializingBean / 自定义 init-method)

  1. BeanPostProcessor#after(后置处理,**AOP 代理在这里生成!**)
4.2 步骤 1:依赖注入

@Service

public class UserService {

@Autowired

private UserDao userDao; // ✅ 步骤 1:此时注入

public UserService() {

System.out.println(userDao); // null(步骤 2 才注入)

}

}

关键事实:

  • 构造方法执行时,userDao 是 null(实例化阶段)
  • 依赖注入发生在实例化之后、初始化之前
4.3 步骤 2:Aware 接口回调

@Service

public class UserService implements BeanNameAware, BeanFactoryAware, ApplicationContextAware {

@Override

public void setBeanName(String name) { // BeanNameAware

System.out.println("Bean 名字:" + name);

}

@Override

public void setBeanFactory(BeanFactory factory) { // BeanFactoryAware

System.out.println("BeanFactory 注入");

}

@Override

public void setApplicationContext(ApplicationContext ctx) { // ApplicationContextAware

System.out.println("ApplicationContext 注入");

}

}

3 个常见 Aware 接口:

接口 注入什么 项目实战
BeanNameAware Bean 的名字 一般不用
BeanFactoryAware BeanFactory 获取其他 Bean
ApplicationContextAware ApplicationContext 项目里用过(拿 Spring 容器)
4.4 步骤 3:BeanPostProcessor#before(Spring 扩展点

@Component

public class MyBeanPostProcessor implements BeanPostProcessor {

@Override

public Object postProcessBeforeInitialization(Object bean, String beanName) {

System.out.println("Before: " + beanName);

return bean; // 可以返回包装后的 bean

}

@Override

public Object postProcessAfterInitialization(Object bean, String beanName) {

System.out.println("After: " + beanName);

return bean;

}

}

这个接口的 3 大作用:

  • AOP 代理生成@EnableAspectJAutoProxy 内部用这个
  • 自定义注解处理
  • Bean 包装(返回代理对象)
4.5 步骤 4:初始化方法(3 种方式

@Service

public class UserService {

// 方式 1:@PostConstruct(JSR-250 注解)

@PostConstruct

public void init() {

System.out.println("@PostConstruct 初始化");

}

// 方式 2:InitializingBean 接口

public class UserService implements InitializingBean {

@Override

public void afterPropertiesSet() throws Exception {

System.out.println("InitializingBean 初始化");

}

}

// 方式 3:自定义 init-method(XML 配置)

// <bean id="userService" class="..." init-method="customInit"/>

public void customInit() {

System.out.println("自定义 init-method 初始化");

}

}

执行顺序(3 种方式):

  1. @PostConstruct

  2. InitializingBean#afterPropertiesSet

  3. 自定义 init-method

4.6 步骤 5:BeanPostProcessor#after(AOP 代理生成!

// AbstractAutowireCapableBeanFactory.doCreateBean()

protected Object initializeBean(...) {

// 1. 依赖注入

// 2. Aware 回调

// 3. BeanPostProcessor#before

applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);

// 4. 初始化方法(@PostConstruct / InitializingBean)

invokeInitMethods(beanName, wrappedBean, mbd);

// 5. BeanPostProcessor#after(**AOP 代理生成!**)

wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

return wrappedBean;

}

关键事实:AOP 代理在 BeanPostProcessor#after 阶段生成(所以 @Transactional 方法被调用时才有事务)。

4.7 项目对应

报表生成 Service:

@Service

public class ReportGeneratorService implements InitializingBean {

@Autowired // 步骤 1:依赖注入

private DataSource dataSource;

@Autowired

private ReportTemplateLoader templateLoader;

@Override // 步骤 2.3:InitializingBean 初始化

public void afterPropertiesSet() throws Exception {

// 报表模板预加载

templateLoader.preload();

}

@Transactional // 步骤 5:AOP 代理在这里加事务拦截

public void generateReport(ReportQuery query) {

// ...

}

}

五、阶段 4:销毁 bean

5.1 触发时机
  • 容器关闭时ctx.close()
  • Web 应用停止时
  • Spring Boot shutdown hook
5.2 3 种销毁方式

@Service

public class UserService {

// 方式 1:@PreDestroy

@PreDestroy

public void cleanup() {

System.out.println("@PreDestroy 销毁");

}

// 方式 2:DisposableBean 接口

public class UserService implements DisposableBean {

@Override

public void destroy() throws Exception {

System.out.println("DisposableBean 销毁");

}

}

// 方式 3:自定义 destroy-method

public void customDestroy() {

System.out.println("自定义 destroy-method 销毁");

}

}

执行顺序: @PreDestroyDisposableBean#destroy自定义 destroy-method

5.3 关键事实:prototype Bean 不会触发销毁

@Service

@Scope("prototype")

public class ShoppingCart { // ⚠️ prototype 的销毁 Spring 不管

@PreDestroy

public void cleanup() { ... } // 不会触发

}

销毁逻辑必须自己写

六、完整生命周期时序图

Spring 启动

1 扫描 @Component/@Service/@Controller/@Repository/@Bean

↓ 生成 BeanDefinition

2 实例化(new UserService())

↓ 构造方法执行

3 依赖注入(@Autowired / @Resource / @Value)

↓ 成员变量赋值

4 Aware 接口回调

↓ BeanNameAware / BeanFactoryAware / ApplicationContextAware

5 BeanPostProcessor#before

↓ 前置处理

6 初始化方法

↓ @PostConstruct → InitializingBean → init-method

7 BeanPostProcessor#after

↓ **AOP 代理生成**(@Transactional / @Async / 自定义 AOP)

8 Bean 放入容器(singleton 缓存)

9 业务使用期

10 容器关闭

11 销毁方法

↓ @PreDestroy → DisposableBean → destroy-method

七、面试官追问应对

追问:Spring Bean 生命周期有哪些阶段?

"4 大阶段

1.Bean 定义(生成 BeanDefinition)

2.实例化 (new 对象,不赋值

3.初始化赋值(依赖注入 → Aware → BeanPostProcessor → 初始化方法)

4.销毁 bean(@PreDestroy → DisposableBean → destroy-method)

关键:AOP 代理在 BeanPostProcessor#after 阶段生成,所以 @Transactional 方法被调用时才有事务。"

追问 2:构造方法和 @PostConstruct 谁先执行?

"构造方法先执行 (实例化阶段),@PostConstruct 后执行(初始化阶段)。

所以构造方法里调用成员变量是 null (依赖还没注入),@PostConstruct 里调用成员变量是有值的(依赖已注入)。

构造方法执行时 redisTemplate 还是 null,@PostConstruct 里 redisTemplate 才有值。"

追问 3:@PostConstruct 和 InitializingBean 哪个先?

"@PostConstruct 先(JSR-250 标准注解,Spring 推荐)。

执行顺序:

1.@PostConstruct

2.InitializingBean#afterPropertiesSet

3.自定义 init-method

推荐用 @PostConstruct(标准化、跨框架)。"

追问 4:AOP 代理什么时候生成?

"BeanPostProcessor#after 阶段生成

这就是为什么 @Transactional / @Async / 自定义 AOP 必须在 Spring 容器管理的 Bean 上才生效,因为代理是在初始化阶段生成的

如果用 new UserService() 创建对象,没有代理,事务不生效。"

追问 5:循环依赖怎么解决?

"3 级缓存

1.singletonObjects:完整 Bean(一级缓存)

2.earlySingletonObjects:早期引用(二级缓存)

3.singletonFactories:ObjectFactory(三级缓存)

解决流程:

  • A 创建 → 暴露 ObjectFactory → 属性注入(发现依赖 B)
  • B 创建 → 暴露 ObjectFactory → 属性注入(发现依赖 A)
  • A 从三级缓存获取早期引用 → B 注入成功 → B 创建完成
  • A 注入 B → A 创建完成

注意:构造方法注入的循环依赖无法解决 (因为构造时还没暴露早期引用),必须用 @Autowired 字段注入或 setter 注入。"

追问 6:prototype Bean 的循环依赖能解决吗?

"不能 。prototype 不放入三级缓存,所以循环依赖会抛 BeanCurrentlyInCreationException

解决:用 @Lazy(延迟加载)。"

八、记忆口诀

"4 大阶段:定义 → 实例化 → 初始化 → 销毁"

"实例化不赋值,初始化才赋值"

"@PostConstruct 先于 InitializingBean"

"AOP 代理在 BeanPostProcessor#after 阶段生成"

"构造方法依赖是 null,@PostConstruct 依赖是有值的"

"3 级缓存解决循环依赖,构造注入无解"

相关推荐
咖啡八杯8 小时前
GoF设计模式——备忘录模式
java·后端·spring·设计模式
Flittly2 天前
【AgentScope Java新手村系列】(16)从RAG到多路检索
java·spring boot·spring
咖啡八杯2 天前
GoF设计模式——中介者模式
java·后端·spring·设计模式
Flittly4 天前
【AgentScope Java新手村系列】(14)人机交互
java·spring boot·spring
唐青枫8 天前
Java Spring WebFlux 实战指南:用 Mono、Flux 和 WebClient 写响应式接口
java·spring
咖啡八杯9 天前
GoF设计模式——策略模式
java·后端·spring·设计模式
Flittly11 天前
【AgentScope Java新手村系列】(11)中断与恢复
java·spring boot·spring
dunky11 天前
Spring 的三级缓存与循环依赖
后端·spring
LDR00616 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术16 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript