Spring Bean 生命周期

​一、图解生命周期 4 大阶段
截屏2026-06-10 16.48
【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)
       ↓
  2. Aware 接口回调(BeanNameAware / BeanFactoryAware / ApplicationContextAware)
       ↓
  3. BeanPostProcessor#before(前置处理)
       ↓
  4. 初始化方法(@PostConstruct / InitializingBean / 自定义 init-method)
       ↓
  5. 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 配置)
    //
    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 销毁");
    }
}
执行顺序: @PreDestroy → DisposableBean#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 里调用成员变量是有值的(依赖已注入)。
老哥 DLQ Demo 里,构造方法执行时 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级缓存解决循环依赖,构造注入无解
prototype Bean,销毁逻辑必须自己写"

posted @ 2026-06-10 15:59  向阳明月  阅读(1)  评论(0)    收藏  举报