1. 程式人生 > 其它 >【Spring】之@PostConstruct , InitializingBean, initMethod,@PreDestroy,DisposableBean,destroyMethod初始化銷燬

【Spring】之@PostConstruct , InitializingBean, initMethod,@PreDestroy,DisposableBean,destroyMethod初始化銷燬

技術標籤:架構spring

1 實驗環境 spring-beans 5.3.1 + 程式碼

package com.learn.webtemplate;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.concurrent.CompletableFuture;

@Service
public class GitHubLookupService implements InitializingBean, DisposableBean {

  private static final Logger logger = LoggerFactory.getLogger(GitHubLookupService.class);

  private final RestTemplate restTemplate;

  public GitHubLookupService(RestTemplateBuilder restTemplateBuilder) {
    this.restTemplate = restTemplateBuilder.build();
    System.out.println("--構造方法----GitHubLookupService");
  }



  @Async
  public CompletableFuture<User> findUser(String user) throws InterruptedException {
    logger.info("Looking up " + user);
    String url = String.format("https://api.github.com/users/%s", user);
    User results = restTemplate.getForObject(url, User.class);
    // Artificial delay of 1s for demonstration purposes
    Thread.sleep(1000L);
    return CompletableFuture.completedFuture(results);
  }

  @PostConstruct
  public void init(){
    System.out.println("
[email protected]
"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("--InitializingBean -- afterPropertiesSet--"); } // 自定義初始化方法 @PreDestroy public void preDestroy(){ System.out.println("[email protected]"); } @Override public void destroy() throws Exception { System.out.println("--DisposableBean -- afterPropertiesSet--"); } // 自定義銷燬方法 }

2 結果

  1. --構造方法----GitHubLookupService
  2. [email protected]
  3. --InitializingBean -- afterPropertiesSet--
  4. // initMethod = "init" 如果指定自定義初始化方法
  5. [email protected]
  6. --DisposableBean --destroy--
  7. // destroyMethod = "myDestroy" 如果指定自定義銷燬方法

3 原始碼解讀

  • 關鍵點:Spring bean 的初始化
  • 第一步:createBeanInstance --> Spring bean例項化構造方法執行;(org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#autowireConstructor) // 571行 --構造方法
    ----GitHubLookupService 輸出 1
  • 第二步:populateBean --> 設值(org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean);
  • 第三步:initializeBean --> 初始化org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean )// 1767行
  • 本文關注的就是初始化的流程:
  • invokeAwareMethods-->applyBeanPostProcessorsBeforeInitialization-->invokeInitMethods-->applyBeanPostProcessorsAfterInitialization(後面稱為初始化三部曲)
  • -->applyBeanPostProcessorsBeforeInitialization 會進行--> InitDestroyAnnotationBeanPostProcessor 初始化銷燬bean處理器執行@PostConstruct--->init() 方法執行 [email protected] 輸出2
  • -->invokeInitMethods 會進行 ((InitializingBean) bean).afterPropertiesSet() --> --InitializingBean -- afterPropertiesSet-- 輸出3
  • 注意這裡還會進行自定義初始化方法(mdb的initMethodName屬性指定)執行即 xml中指定@Bean(initMethod = "init")方法執行;4
  • -->
  • 第四步:registerDisposableBeanIfNecessary---->org.springframework.beans.factory.support.AbstractBeanFactory#registerDisposableBeanIfNecessary 註冊銷燬方法
  • 第五步:當用戶執行 kill -15 Pid
  • 會回撥:applicationContext 啟動時註冊好的(Runtime.getRuntime().addShutdownHook(this.shutdownHook);)org.springframework.context.support.AbstractApplicationContext#registerShutdownHook-->shutdownHook方法。
  • --->org.springframework.context.support.AbstractApplicationContext#doClose
  • --->org.springframework.context.support.AbstractApplicationContext#destroyBeans
  • --->org.springframework.beans.factory.support.DefaultListableBeanFactory#destroySingletons
  • --->org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#destroySingletons
  • --->org.springframework.beans.factory.support.DefaultListableBeanFactory#destroySingleton
  • --->org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#destroyBean // 單個bean的銷燬
  • bean.destroy()--->方法執行org.springframework.beans.factory.support.DisposableBeanAdapter#destroy
  • --->org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#postProcessBeforeDestruction // 首先執行-->初始化銷燬bean處理器執行
  • -->org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata#invokeDestroyMethods
  • -->preDestroy 方法呼叫---->[email protected] 輸出5
  • -->DisposableBean 介面 ---> org.springframework.beans.factory.DisposableBean#destroy --->--DisposableBean -- destroy -- 輸出6
  • -->invokeCustomDestroyMethod 自定義銷燬方法-->@Bean(destroyMethod = "myDestroy") -->自己指定的邏輯輸出7

4 總結

  • 1 現在系統中初始化(或者銷燬)一般都是三選一 @Bean(initMethod = "init", destroyMethod = "myDestroy") 或者實現(InitializingBean 和 DisposableBean)介面 更多的是使用註解 @PostConstruct 和 @PreDestroy
  • 2 涉及到父類初始化和銷燬考慮優先順序,初始化一般都是從父類開始,銷燬都是從子類方法開始,原始碼陣列實現如下:
  • initMethods.addAll(0, currInitMethods); // 祖先最先初始化
    destroyMethods.addAll(currDestroyMethods); // 祖先最後銷燬
  • 3 kill -15 pid 實現關機,觸發jvm關閉機制可以更進一步探索