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 级缓存解决循环依赖,构造注入无解"

相关推荐
程序员小羊!1 小时前
16 JAVA MySQL 8.0
java·开发语言·mysql
Dovis(誓平步青云)1 小时前
《QT学习第五篇:QSS美化界面与API绘图》
开发语言·数据库·qt·学习·时序数据库·开源智能体
无忧.芙桃1 小时前
数据结构之栈
c语言·开发语言·数据结构
wyhwust1 小时前
web应用技术--springboot01
java·开发语言
想你依然心痛1 小时前
数据库技术在电力业务中的核心应用场景
java·开发语言·数据库
摇滚侠1 小时前
SpringMVC 入门到实战 域对象共享数据 33-43
java·后端·spring·intellij-idea
Shadow(⊙o⊙)1 小时前
QT常用控件3.0,font字体设置,toolTip提示,focusPolicy焦点定位原则,中型控件StyleSheet样式表。
服务器·开发语言·前端·c++·qt
Shadow(⊙o⊙)2 小时前
QT常用控件2.0,windowOpacity窗口透明度,Cursor光标设置
开发语言·c++·qt
weixin_523185322 小时前
Spring事务为什么会失效?常见场景与解决方案总结
java·数据库·spring