单例bean的生命周期有哪些?比如我想在初始化时执行方法,或者说项目开始时执行方法,bean销毁时执行方法,怎么实现 原理是什么?

单例 Bean 的完整生命周期及初始化/销毁方法实现


一、单例 Bean 的完整生命周期阶段


生命周期流程图


```

容器启动

   ↓

1. 实例化(构造方法)

   ↓

2. 属性注入(setter/字段注入)

   ↓

3. Aware接口回调(BeanNameAware等)

   ↓

4. BeanPostProcessor前置处理

   ↓

5. @PostConstruct方法执行

   ↓

6. InitializingBean.afterPropertiesSet()

   ↓

7. 自定义init-method

   ↓

8. BeanPostProcessor后置处理

   ↓

9. Bean就绪可用

   ↓

容器关闭

   ↓

10. @PreDestroy方法执行

   ↓

11. DisposableBean.destroy()

   ↓

12. 自定义destroy-method

```


二、初始化方法实现的 5 种方式


方式1:@PostConstruct 注解(最常用、推荐)


```java

@Component

public class MyService {

   

   @PostConstruct  // 项目启动时自动执行

   public void init() {

       System.out.println("1. @PostConstruct 初始化方法执行");

       System.out.println("时机:在所有依赖注入完成后,InitializingBean之前");

       

       // 初始化操作:加载配置、预热缓存、建立连接等

       loadConfiguration();

       warmUpCache();

       initDatabaseConnection();

   }

   

   private void loadConfiguration() {

       // 加载配置

   }

   

   private void warmUpCache() {

       // 预热缓存

   }

   

   private void initDatabaseConnection() {

       // 初始化数据库连接

   }

}

```


方式2:实现 InitializingBean 接口


```java

@Component  

public class CacheService implements InitializingBean {

   

   private Map<String, Object> cache;

   

   @Override  // 项目启动时自动执行

   public void afterPropertiesSet() throws Exception {

       System.out.println("2. InitializingBean.afterPropertiesSet() 执行");

       System.out.println("时机:在@PostConstruct之后,init-method之前");

       

       // 初始化缓存

       cache = new ConcurrentHashMap<>();

       preloadCache();

   }

   

   private void preloadCache() {

       // 预加载热点数据

       cache.put("config", loadConfigFromDB());

       cache.put("hotProducts", loadHotProducts());

   }

}

```


方式3:@Bean 注解的 initMethod 属性


```java

@Configuration

public class AppConfig {

   

   @Bean(initMethod = "init", destroyMethod = "cleanup")

   public ExternalService externalService() {

       return new ExternalService();

   }

}


// 普通类,不需要@Component

public class ExternalService {

   

   public void init() {  // 方法名任意

       System.out.println("3. 自定义init-method执行");

       System.out.println("时机:在InitializingBean之后");

       

       // 外部服务初始化

       connectToExternalAPI();

       validateCredentials();

   }

   

   public void cleanup() {

       System.out.println("清理外部连接");

   }

}

```


方式4:SmartInitializingSingleton(所有单例Bean初始化完成后)


```java

@Component

public class GlobalInitializer implements SmartInitializingSingleton {

   

   @Autowired

   private List<SomeService> services;  // 可以注入所有相关Bean

   

   @Override

   // 当所有单例Bean都初始化完成后执行

   public void afterSingletonsInstantiated() {

       System.out.println("4. SmartInitializingSingleton执行");

       System.out.println("时机:所有单例Bean都完成初始化后");

       System.out.println("当前已初始化Bean数量: " + services.size());

       

       // 全局初始化操作

       initializeCrossServiceDependencies();

       startBackgroundJobs();

   }

   

   private void initializeCrossServiceDependencies() {

       // 解决跨服务依赖

   }

}

```


方式5:CommandLineRunner / ApplicationRunner(应用启动后)


```java

@Component

@Order(1)  // 控制执行顺序,数字越小优先级越高

public class StartupRunner implements CommandLineRunner {

   

   @Override

   // 在Spring Boot应用完全启动后执行

   public void run(String... args) throws Exception {

       System.out.println("5. CommandLineRunner执行");

       System.out.println("时机:Spring Boot应用完全启动后");

       

       // 应用启动后需要执行的操作

       checkExternalServices();

       sendStartupNotification();

       scheduleRegularTasks();

   }

}


// ApplicationRunner 使用键值对参数

@Component

@Order(2)

public class AnotherRunner implements ApplicationRunner {

   

   @Override

   public void run(ApplicationArguments args) throws ApplicationRunner {

       System.out.println("ApplicationRunner执行");

       System.out.println("启动参数: " + args.getOptionNames());

   }

}

```


三、销毁方法实现的 3 种方式


方式1:@PreDestroy 注解(最常用、推荐)


```java

@Component

public class ResourceHolder {

   

   private List<Connection> connections = new ArrayList<>();

   private ScheduledExecutorService executor;

   

   @PostConstruct

   public void init() {

       executor = Executors.newScheduledThreadPool(2);

       System.out.println("线程池初始化完成");

   }

   

   @PreDestroy  // 应用关闭时自动执行

   public void cleanup() {

       System.out.println("1. @PreDestroy 清理方法执行");

       

       // 1. 关闭线程池

       if (executor != null) {

           executor.shutdown();

           try {

               if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {

                   executor.shutdownNow();

               }

           } catch (InterruptedException e) {

               executor.shutdownNow();

               Thread.currentThread().interrupt();

           }

       }

       

       // 2. 关闭数据库连接

       connections.forEach(this::closeConnection);

       

       // 3. 清理缓存

       clearCaches();

       

       System.out.println("所有资源已清理完成");

   }

}

```


方式2:实现 DisposableBean 接口


```java

@Component

public class DatabasePool implements DisposableBean {

   

   private DataSource dataSource;

   

   @Override  // 应用关闭时自动执行

   public void destroy() throws Exception {

       System.out.println("2. DisposableBean.destroy() 执行");

       

       if (dataSource instanceof HikariDataSource) {

           ((HikariDataSource) dataSource).close();

           System.out.println("数据库连接池已关闭");

       }

   }

}

```


方式3:@Bean 注解的 destroyMethod 属性


```java

@Configuration  

public class DataSourceConfig {

   

   @Bean(destroyMethod = "shutdown")

   public ExecutorService executorService() {

       return Executors.newFixedThreadPool(10);

   }

   

   @Bean(destroyMethod = "close")  // 对于有close()方法的Bean,Spring会自动检测

   public DataSource dataSource() {

       HikariConfig config = new HikariConfig();

       // 配置数据源

       return new HikariDataSource(config);

   }

}

```


四、完整示例:资源管理 Bean


```java

@Component

@Slf4j

public class ResourceManager implements

       InitializingBean, DisposableBean, ApplicationListener<ContextClosedEvent> {

   

   // === 资源定义 ===

   private ScheduledExecutorService scheduler;

   private Connection externalApiConnection;

   private Map<String, Object> localCache;

   private WebSocketClient webSocketClient;

   

   // === 1. 构造方法 ===

   public ResourceManager() {

       log.info("1. 构造方法执行 - 创建ResourceManager实例");

   }

   

   // === 2. 属性注入 ===

   @Value("${app.api.timeout:5000}")

   private int apiTimeout;

   

   @Autowired

   private Environment env;

   

   // === 3. @PostConstruct ===

   @PostConstruct

   public void postConstructInit() {

       log.info("3. @PostConstruct - 第一阶段初始化");

       

       // 初始化本地缓存

       localCache = new ConcurrentHashMap<>();

       localCache.put("startupTime", System.currentTimeMillis());

       

       // 创建线程池(但不启动)

       scheduler = Executors.newScheduledThreadPool(3,

           new ThreadFactoryBuilder()

               .setNameFormat("resource-mgr-%d")

               .setDaemon(true)

               .build());

   }

   

   // === 4. InitializingBean ===

   @Override

   public void afterPropertiesSet() throws Exception {

       log.info("4. InitializingBean.afterPropertiesSet() - 第二阶段初始化");

       

       // 连接外部API

       externalApiConnection = connectToExternalAPI();

       

       // 启动WebSocket客户端

       if (env.acceptsProfiles(Profiles.of("prod", "staging"))) {

           webSocketClient = startWebSocketClient();

       }

       

       // 启动定时任务

       startScheduledTasks();

   }

   

   // === 5. 自定义初始化方法 ===

   public void customInit() {

       log.info("5. 自定义初始化方法 - 第三阶段初始化");

       

       // 预热缓存

       preloadCache();

       

       // 发送启动通知

       sendStartupNotification();

   }

   

   // === 6. 业务方法 ===

   public Object getResource(String key) {

       return localCache.get(key);

   }

   

   // === 7. @PreDestroy ===

   @PreDestroy

   public void preDestroyCleanup() {

       log.info("7. @PreDestroy - 第一阶段清理");

       

       // 清理缓存

       localCache.clear();

       log.info("本地缓存已清理");

   }

   

   // === 8. DisposableBean ===  

   @Override

   public void destroy() throws Exception {

       log.info("8. DisposableBean.destroy() - 第二阶段清理");

       

       // 关闭外部连接

       if (externalApiConnection != null) {

           externalApiConnection.close();

           log.info("外部API连接已关闭");

       }

       

       // 关闭WebSocket

       if (webSocketClient != null) {

           webSocketClient.close();

           log.info("WebSocket连接已关闭");

       }

   }

   

   // === 9. 自定义销毁方法 ===

   public void customDestroy() {

       log.info("9. 自定义销毁方法 - 第三阶段清理");

       

       // 关闭线程池

       if (scheduler != null) {

           scheduler.shutdownNow();

           log.info("线程池已关闭");

       }

   }

   

   // === 10. 监听容器关闭事件 ===

   @Override

   public void onApplicationEvent(ContextClosedEvent event) {

       log.info("10. 收到ContextClosedEvent - 容器开始关闭");

       

       // 确保所有清理工作完成

       waitForCleanupCompletion();

       log.info("所有清理工作已完成");

   }

   

   // === 辅助方法 ===

   private Connection connectToExternalAPI() {

       log.info("连接到外部API,超时设置: {}ms", apiTimeout);

       return null; // 实际返回连接对象

   }

   

   private WebSocketClient startWebSocketClient() {

       log.info("启动WebSocket客户端");

       return null;

   }

   

   private void startScheduledTasks() {

       scheduler.scheduleAtFixedRate(() -> {

           refreshCache();

       }, 0, 5, TimeUnit.MINUTES);

       log.info("定时任务已启动");

   }

   

   private void preloadCache() {

       // 预加载数据

       localCache.put("config", loadConfig());

       localCache.put("users", loadActiveUsers());

       log.info("缓存预热完成,已加载{}项数据", localCache.size());

   }

}

```


五、Spring Boot 特定的启动方式


1. ApplicationReadyEvent(应用完全就绪后)


```java

@Component

public class ApplicationReadyListener {

   

   @EventListener(ApplicationReadyEvent.class)

   public void onApplicationReady() {

       System.out.println("应用完全就绪,可以开始处理请求");

       System.out.println("时机:在所有Bean初始化、CommandLineRunner执行之后");

       

       // 此时可以:

       // 1. 发送应用启动成功通知

       // 2. 注册到服务注册中心

       // 3. 开始接收外部请求

   }

}

```


2. SpringApplication 的 ApplicationRunner


```java

@SpringBootApplication

public class MyApplication {

   

   public static void main(String[] args) {

       SpringApplication app = new SpringApplication(MyApplication.class);

       

       // 添加初始化器

       app.addInitializers(new ApplicationContextInitializer<ConfigurableApplicationContext>() {

           @Override

           public void initialize(ConfigurableApplicationContext context) {

               System.out.println("ApplicationContext初始化前执行");

           }

       });

       

       // 添加监听器

       app.addListeners(new ApplicationListener<ApplicationEvent>() {

           @Override

           public void onApplicationEvent(ApplicationEvent event) {

               if (event instanceof ApplicationStartedEvent) {

                   System.out.println("应用启动事件");

               }

           }

       });

       

       app.run(args);

   }

}

```


六、实际应用场景示例


场景1:缓存预热服务


```java

@Component

@Slf4j

public class CacheWarmupService {

   

   @Autowired

   private ProductRepository productRepository;

   

   @Autowired  

   private CacheManager cacheManager;

   

   @Autowired

   private MetricRegistry metrics;

   

   @PostConstruct

   @Order(Ordered.LOWEST_PRECEDENCE)  // 最后执行

   public void warmUpAllCaches() {

       log.info("开始全局缓存预热...");

       long startTime = System.currentTimeMillis();

       

       // 1. 预热商品缓存

       warmUpProductCache();

       

       // 2. 预热用户缓存  

       warmUpUserCache();

       

       // 3. 预热配置缓存

       warmUpConfigCache();

       

       long duration = System.currentTimeMillis() - startTime;

       log.info("缓存预热完成,耗时: {}ms", duration);

       

       // 记录指标

       metrics.timer("cache.warmup.time").update(duration, TimeUnit.MILLISECONDS);

   }

   

   @PreDestroy

   public void clearAllCaches() {

       log.info("应用关闭,清理所有缓存...");

       

       // 清理所有缓存

       cacheManager.getCacheNames().forEach(cacheName -> {

           Cache cache = cacheManager.getCache(cacheName);

           if (cache != null) {

               cache.clear();

               log.debug("清理缓存: {}", cacheName);

           }

       });

       

       log.info("所有缓存已清理");

   }

}

```


场景2:WebSocket 连接管理


```java

@Component

public class WebSocketManager implements SmartLifecycle {

   

   private WebSocketSession session;

   private volatile boolean running = false;

   

   @PostConstruct

   public void init() {

       log.info("WebSocket管理器初始化");

   }

   

   @Override

   public void start() {

       if (!running) {

           log.info("启动WebSocket连接...");

           try {

               session = connectToServer();

               running = true;

               log.info("WebSocket连接建立成功");

           } catch (Exception e) {

               log.error("WebSocket连接失败", e);

           }

       }

   }

   

   @Override

   public void stop() {

       if (running) {

           log.info("关闭WebSocket连接...");

           try {

               if (session != null && session.isOpen()) {

                   session.close();

               }

           } catch (Exception e) {

               log.error("关闭WebSocket连接时出错", e);

           } finally {

               running = false;

               session = null;

           }

       }

   }

   

   @PreDestroy

   public void cleanup() {

       stop();

       log.info("WebSocket管理器清理完成");

   }

   

   @Override

   public boolean isRunning() {

       return running;

   }

}

```


场景3:分布式锁初始化


```java

@Component

public class DistributedLockInitializer implements ApplicationRunner {

   

   @Autowired

   private RedissonClient redissonClient;

   

   @Value("${app.lock.keys}")

   private List<String> lockKeys;

   

   @Override

   public void run(ApplicationArguments args) throws Exception {

       log.info("初始化分布式锁...");

       

       // 预创建所有需要的锁,避免运行时创建的开销

       lockKeys.forEach(key -> {

           RLock lock = redissonClient.getLock(key);

           lock.tryLock(0, TimeUnit.SECONDS);  // 立即释放,只是为了初始化

           lock.unlock();

       });

       

       log.info("已初始化 {} 个分布式锁", lockKeys.size());

   }

}

```


七、原理深入解析


1. 初始化执行顺序的原理


```java

// Spring 内部调用顺序(简化版)

public abstract class AbstractAutowireCapableBeanFactory {

   

   protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {

       

       // 1. 执行 Aware 接口方法

       invokeAwareMethods(beanName, bean);

       

       // 2. BeanPostProcessor 前置处理

       wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);

       

       try {

           // 3. 执行初始化方法

           invokeInitMethods(beanName, wrappedBean, mbd);

       } catch (Throwable ex) {

           throw new BeanCreationException(...);

       }

       

       // 4. BeanPostProcessor 后置处理

       wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

       

       return wrappedBean;

   }

   

   protected void invokeInitMethods(String beanName, Object bean, RootBeanDefinition mbd)

           throws Throwable {

       

       boolean isInitializingBean = bean instanceof InitializingBean;

       

       // 3.1 先执行 @PostConstruct 方法(通过 CommonAnnotationBeanPostProcessor)

       // 3.2 再执行 InitializingBean.afterPropertiesSet()

       if (isInitializingBean) {

           ((InitializingBean) bean).afterPropertiesSet();

       }

       

       // 3.3 最后执行自定义的 init-method

       if (mbd != null && bean.getClass() != NullBean.class) {

           String initMethodName = mbd.getInitMethodName();

           if (StringUtils.hasLength(initMethodName)) {

               invokeCustomInitMethod(beanName, bean, initMethodName);

           }

       }

   }

}

```


2. 销毁执行顺序的原理


```java

public class DisposableBeanAdapter implements DisposableBean {

   

   @Override

   public void destroy() throws Exception {

       // 1. 先执行 @PreDestroy 方法

       if (this.preDestroyMethod != null) {

           ReflectionUtils.invokeMethod(this.preDestroyMethod, this.bean);

       }

       

       // 2. 再执行 DisposableBean.destroy()

       if (this.disposableBean != null) {

           this.disposableBean.destroy();

       }

       

       // 3. 最后执行自定义的 destroy-method

       if (this.destroyMethod != null) {

           ReflectionUtils.invokeMethod(this.destroyMethod, this.bean);

       }

   }

}

```


3. 生命周期管理的底层实现


```java

// Spring 通过 BeanPostProcessor 管理生命周期

@Component

public class CommonAnnotationBeanPostProcessor implements BeanPostProcessor {

   

   // 处理 @PostConstruct

   @Override

   public Object postProcessBeforeInitialization(Object bean, String beanName) {

       // 查找并执行 @PostConstruct 方法

       LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());

       metadata.invokeInitMethods(bean, beanName);

       return bean;

   }

   

   // 处理 @PreDestroy

   @Override

   public Object postProcessAfterInitialization(Object bean, String beanName) {

       // 注册销毁回调

       if (requiresDestruction(bean, beanName)) {

           registerDestructionCallback(beanName, bean);

       }

       return bean;

   }

}

```


八、最佳实践总结


选择指南


场景 推荐方式 理由

普通的初始化逻辑 @PostConstruct 简单、直观、解耦

需要实现接口的Bean InitializingBean 与框架集成更好

第三方库的Bean @Bean(initMethod) 不修改源码

所有Bean初始化完成后 SmartInitializingSingleton 处理跨Bean依赖

应用完全启动后 ApplicationRunner 确保所有服务就绪

资源清理 @PreDestroy 简单可靠

复杂资源管理 DisposableBean + @PreDestroy 分级清理


注意事项


1. 执行顺序问题:多个初始化方法会按固定顺序执行

2. 异常处理:初始化失败会导致Bean创建失败

3. 循环依赖:避免在初始化方法中引用可能产生循环依赖的Bean

4. 性能影响:初始化方法中的耗时操作会影响启动时间

5. 事务问题:初始化方法中的数据库操作不受事务管理


调试技巧


```java

// 查看Bean的初始化状态

@Component

public class LifecycleDebugger implements BeanPostProcessor {

   

   @Override

   public Object postProcessBeforeInitialization(Object bean, String beanName) {

       System.out.println("准备初始化: " + beanName);

       return bean;

   }

   

   @Override

   public Object postProcessAfterInitialization(Object bean, String beanName) {

       System.out.println("初始化完成: " + beanName);

       return bean;

   }

}


// 使用 actuator 端点查看Bean信息

// application.yml

management:

 endpoints:

   web:

     exposure:

       include: beans

// 访问: http://localhost:8080/actuator/beans

```


通过合理使用这些生命周期方法,可以确保应用的优雅启动和安全关闭,有效管理资源。