Bean 生命周期

Spring Bean 从被容器创建到最终销毁,经历一套固定的生命周期阶段。理解这些阶段有助于正确使用初始化/销毁回调,以及排查 Bean 状态异常问题。


生命周期全流程

1. 实例化(Instantiation)
   └── 调用构造器,创建 Bean 实例

2. 属性注入(Property Population)
   └── 填充 @Autowired、@Value 等依赖

3. Aware 接口回调
   ├── BeanNameAware.setBeanName()
   ├── BeanClassLoaderAware.setBeanClassLoader()
   ├── BeanFactoryAware.setBeanFactory()
   ├── EnvironmentAware.setEnvironment()
   ├── ApplicationContextAware.setApplicationContext()
   └── (其他 Aware 接口...)

4. BeanPostProcessor#postProcessBeforeInitialization()
   └── AOP 代理、@Validated 增强等在此介入

5. 初始化(Initialization)
   ├── @PostConstruct 标注的方法
   ├── InitializingBean.afterPropertiesSet()
   └── @Bean(initMethod = "...") 指定的方法

6. BeanPostProcessor#postProcessAfterInitialization()
   └── AOP 代理对象在此生成(替换原始 Bean)

7. Bean 就绪,放入容器(singletonObjects)

        ↓ 应用运行 ↓

8. 销毁(Destruction)
   ├── @PreDestroy 标注的方法
   ├── DisposableBean.destroy()
   └── @Bean(destroyMethod = "...") 指定的方法

销毁回调仅对单例(Singleton) Bean 生效;原型(Prototype)Bean 由容器创建后即交出管理,不会触发销毁方法。


一、实例化

Spring 优先使用无参构造器,若只有有参构造器则自动注入参数:

@Service
public class OrderService {
 
    private final OrderRepository repo;
    private final MailService mailService;
 
    // 单构造器:Spring 自动注入,无需 @Autowired
    public OrderService(OrderRepository repo, MailService mailService) {
        this.repo = repo;
        this.mailService = mailService;
        // 注意:此时 @Autowired 字段尚未注入,不能在构造器中使用字段注入的依赖
    }
}

依赖注入方式详见 IOC与DI


二、Aware 接口

实现 Aware 接口让 Bean 获取容器内部信息,但会造成与 Spring 的强耦合,非必要不使用

@Component
public class SpringContextHolder
        implements ApplicationContextAware, BeanNameAware, EnvironmentAware {
 
    private static ApplicationContext context;
    private String beanName;
    private Environment environment;
 
    // 3-a:BeanNameAware — 获取当前 Bean 在容器中的名称
    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        // 此时属性注入已完成,可以安全使用字段
    }
 
    // 3-b:ApplicationContextAware — 获取整个 ApplicationContext
    @Override
    public void setApplicationContext(ApplicationContext ctx) {
        context = ctx;
    }
 
    // 3-c:EnvironmentAware — 获取 Environment(读取配置属性)
    @Override
    public void setEnvironment(Environment env) {
        this.environment = env;
    }
 
    // 静态工具方法:在非 Spring 管理的类中手动获取 Bean
    public static <T> T getBean(Class<T> clazz) {
        return context.getBean(clazz);
    }
 
    public static String getProperty(String key) {
        return context.getBean(Environment.class).getProperty(key);
    }
}

常用 Aware 接口:

接口注入内容典型用途
BeanNameAware当前 Bean 的注册名日志、区分同类型多实例
BeanFactoryAwareBeanFactory 实例编程式获取 Bean
ApplicationContextAwareApplicationContext 实例静态工具类获取 Bean
EnvironmentAwareEnvironment 实例读取配置属性
ResourceLoaderAwareResourceLoader 实例加载类路径资源
MessageSourceAwareMessageSource 实例国际化消息
ApplicationEventPublisherAwareApplicationEventPublisher发布事件(也可直接注入)

三、BeanPostProcessor

BeanPostProcessor 是 Spring 最强大的扩展点,对容器中所有 Bean 生效

@Component
@Slf4j
public class TimingBeanPostProcessor implements BeanPostProcessor {
 
    // 初始化前(@PostConstruct 执行之前)
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        log.debug("Before init: {}", beanName);
        return bean;   // 必须返回 bean(或替换后的对象)
    }
 
    // 初始化后(AOP 代理在此生成)
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        log.debug("After init: {}", beanName);
        // 可以在这里包装 Bean,返回代理对象
        return bean;
    }
}

Spring 内部大量使用 BeanPostProcessor

BeanPostProcessor作用
AutowiredAnnotationBeanPostProcessor处理 @Autowired@Value
CommonAnnotationBeanPostProcessor处理 @PostConstruct@PreDestroy@Resource
AnnotationAwareAspectJAutoProxyCreator生成 AOP 代理对象
PersistenceAnnotationBeanPostProcessor处理 JPA @PersistenceContext

四、初始化方法

三种方式执行顺序固定@PostConstructafterPropertiesSet()initMethod

@Service
@Slf4j
public class CacheService implements InitializingBean {
 
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
 
    @Autowired
    private UserRepository userRepository;
 
    // 方式一:@PostConstruct(推荐,JSR-250 标准,无 Spring 耦合)
    @PostConstruct
    public void warmUp() {
        log.info("缓存预热开始...");
        // 此时所有依赖已注入,可以安全使用
        List<User> hotUsers = userRepository.findTopActive(100);
        hotUsers.forEach(u -> redisTemplate.opsForValue().set("user:" + u.getId(), u));
        log.info("缓存预热完成,共加载 {} 个用户", hotUsers.size());
    }
 
    // 方式二:InitializingBean(Spring 接口,有耦合,不推荐)
    @Override
    public void afterPropertiesSet() {
        log.info("afterPropertiesSet 执行");
    }
}
 
// 方式三:@Bean(initMethod = "...")(适合第三方类,无法修改源码时)
@Configuration
public class ThirdPartyConfig {
 
    @Bean(initMethod = "init", destroyMethod = "close")
    public HeavyResource heavyResource() {
        return new HeavyResource();   // HeavyResource.init() 在 Bean 就绪后调用
    }
}

@PostConstruct 的典型用途

@Component
public class ApplicationStartupRunner {
 
    @Autowired
    private DataSource dataSource;
 
    @PostConstruct
    public void validateDatabase() {
        // 依赖注入完成后立即验证数据库连通性
        try (Connection conn = dataSource.getConnection()) {
            log.info("数据库连接验证通过: {}", conn.getMetaData().getURL());
        } catch (SQLException e) {
            throw new IllegalStateException("数据库连接失败,应用启动中止", e);
        }
    }
}

五、销毁方法

三种方式执行顺序:@PreDestroydestroy()destroyMethod

@Service
@Slf4j
public class ResourceService implements DisposableBean {
 
    private ScheduledExecutorService scheduler;
    private HttpClient httpClient;
 
    @PostConstruct
    public void init() {
        scheduler = Executors.newScheduledThreadPool(4);
        httpClient = HttpClient.newHttpClient();
    }
 
    // 方式一:@PreDestroy(推荐)
    @PreDestroy
    public void cleanup() {
        log.info("关闭 HTTP 客户端...");
        httpClient = null;
    }
 
    // 方式二:DisposableBean(不推荐,有 Spring 耦合)
    @Override
    public void destroy() throws Exception {
        log.info("关闭调度器...");
        scheduler.shutdown();
        if (!scheduler.awaitTermination(10, TimeUnit.SECONDS)) {
            scheduler.shutdownNow();
        }
    }
}

原型(Prototype)Bean:Spring 创建后即交出控制权,不调用 @PreDestroydestroy()。若需清理,需手动实现或使用 @Bean(destroyMethod = "") 阻止自动推断(防止调用 close()/shutdown() 等公开方法)。


六、SmartLifecycle — 容器级别生命周期

SmartLifecycle 控制 Bean 随 Spring 容器启动/停止的行为,与 Bean 初始化回调不同:Bean 初始化回调在 Bean 就绪时触发,而 SmartLifecycle 在整个容器启动/关闭时触发。

@Component
@Slf4j
public class MessageConsumer implements SmartLifecycle {
 
    private volatile boolean running = false;
    private final ScheduledExecutorService poller =
        Executors.newSingleThreadScheduledExecutor();
 
    // 容器启动完成后调用(所有 Bean 就绪之后)
    @Override
    public void start() {
        log.info("消息消费者启动...");
        poller.scheduleAtFixedRate(this::poll, 0, 1, TimeUnit.SECONDS);
        running = true;
    }
 
    // 容器关闭时调用(异步,调用 callback.run() 通知 Spring 关闭完成)
    @Override
    public void stop(Runnable callback) {
        log.info("消息消费者停止...");
        poller.shutdown();
        running = false;
        callback.run();   // 必须调用,否则 Spring 会等待超时
    }
 
    @Override
    public boolean isRunning() {
        return running;
    }
 
    // phase 值越小越早启动、越晚停止;越大越晚启动、越早停止
    // 默认 Integer.MAX_VALUE / 2
    @Override
    public int getPhase() {
        return 100;   // 优先于默认值更早启动
    }
 
    // 是否在容器 refresh 后自动启动(默认 false)
    @Override
    public boolean isAutoStartup() {
        return true;
    }
 
    private void poll() {
        // 拉取消息处理逻辑
    }
}

七、完整执行顺序验证

@Component
@Slf4j
public class LifecycleDemoBean
        implements BeanNameAware, ApplicationContextAware,
                   InitializingBean, DisposableBean {
 
    // 1. 构造器
    public LifecycleDemoBean() {
        log.info("① 构造器");
    }
 
    // 2. 属性注入(@Autowired)— 由 AutowiredAnnotationBeanPostProcessor 处理
 
    // 3. Aware 接口
    @Override
    public void setBeanName(String name) {
        log.info("③ setBeanName: {}", name);
    }
 
    @Override
    public void setApplicationContext(ApplicationContext ctx) {
        log.info("③ setApplicationContext");
    }
 
    // 4. BeanPostProcessor#before(框架内部,日志见 TimingBeanPostProcessor)
 
    // 5a. @PostConstruct
    @PostConstruct
    public void postConstruct() {
        log.info("⑤ @PostConstruct");
    }
 
    // 5b. InitializingBean
    @Override
    public void afterPropertiesSet() {
        log.info("⑤ afterPropertiesSet");
    }
 
    // 6. BeanPostProcessor#after(AOP 代理在此生成)
 
    // 8a. @PreDestroy
    @PreDestroy
    public void preDestroy() {
        log.info("⑧ @PreDestroy");
    }
 
    // 8b. DisposableBean
    @Override
    public void destroy() {
        log.info("⑧ DisposableBean.destroy()");
    }
}

输出顺序:

① 构造器
③ setBeanName: lifecycleDemoBean
③ setApplicationContext
⑤ @PostConstruct
⑤ afterPropertiesSet
(应用运行...)
⑧ @PreDestroy
⑧ DisposableBean.destroy()

常见误区

误区正确理解
在构造器中使用 @Autowired 字段构造器执行时属性注入尚未完成;改用构造器注入
Prototype Bean 期望 @PreDestroy 执行Spring 不管理 Prototype 的销毁,需手动清理
@PostConstruct 中启动异步任务容器未完全就绪;改用 SmartLifecycle.start()ApplicationReadyEvent
BeanPostProcessor 依赖普通 BeanBeanPostProcessor 过早实例化,其依赖可能无法被 AOP 代理

相关链接

  • IOC与DI — 依赖注入方式(构造器/setter/field)
  • Bean作用域 — Singleton/Prototype 等作用域对生命周期的影响
  • AOP — BeanPostProcessor 生成代理对象的时机
  • 循环依赖 — 三级缓存与生命周期的交互
  • 自动配置 — Bean 定义加载与条件评估阶段
  • 优雅停机 — 容器关闭时销毁回调的触发顺序
  • 事件机制ApplicationReadyEvent 替代 @PostConstruct 的场景