【Spring】之@PostConstruct , InitializingBean, initMethod,@PreDestroy,DisposableBean,destroyMethod初始化銷燬
阿新 • • 發佈:2020-12-13
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 結果
- --構造方法----GitHubLookupService
- [email protected]
- --InitializingBean -- afterPropertiesSet--
- // initMethod = "init" 如果指定自定義初始化方法
- [email protected]
- --DisposableBean --destroy--
- // destroyMethod = "myDestroy" 如果指定自定義銷燬方法
3 原始碼解讀
- 關鍵點:Spring bean 的初始化
- 第一步:createBeanInstance --> Spring bean例項化構造方法執行;(org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#autowireConstructor) // 571行 --構造方法
- 第二步: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關閉機制可以更進一步探索