摘要:加載的時候構(gòu)造函數(shù)什么時候調(diào)用什么時候調(diào)用實現(xiàn)了接口的中的和什么時候調(diào)用你是否清楚呢如果清楚的話可以直接忽略該篇文章最近來了幾個新人,被問了一個和生命周期相關(guān)的一個知識點,解決新人的問題后自己再寫了一個,目的是為了清晰的描述整個的生命周期。
Spring加載bean的時候構(gòu)造函數(shù)什么時候調(diào)用、@PostConstruct什么時候調(diào)用、實現(xiàn)了BeanPostProcessor接口的bean中的postProcessAfterInitialization和postProcessBeforeInitialization什么時候調(diào)用?你是否清楚呢?如果清楚的話可以直接忽略該篇文章!??!
最近來了幾個新人,被問了一個和bean生命周期相關(guān)的一個知識點,解決新人的問題后自己再寫了一個demo,目的是為了清晰的描述整個bean的生命周期。
注意注意,以下demo有五個類,可能會引起部分人不適,建議可以直接跳到最后看最終總結(jié),或者自己下載源碼運行下。給出一個demo
demo地址:https://github.com/wiatingpub...
首先給出一個實現(xiàn)了BeanFactoryPostProcessor的類,目的是為了比較清晰的看出postProcessBeanFactory接口被調(diào)用的時間點。
/** * BeanFactoryPostProcessor是bean工廠的處理器 */ @Component public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { public MyBeanFactoryPostProcessor() { super(); System.out.println("【BeanFactoryPostProcessor】實現(xiàn)類postProcessBeanFactory的構(gòu)造函數(shù)"); } // 允許我們在工廠里所有的bean被加載進(jìn)來后但是還沒初始化前,對所有bean的屬性進(jìn)行修改也可以add屬性值,該操作在對應(yīng)bean的構(gòu)造函數(shù)執(zhí)行前 @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0) throws BeansException { System.out .println("【BeanFactoryPostProcessor.postProcessBeanFactory】,來自MyBeanFactoryPostProcessor"); //獲取到Spring中所有的beanName String[] beanStr = arg0.getBeanDefinitionNames(); //循環(huán)打印 for (String beanName : beanStr) { System.out.print("bean name:" + beanName + ";"); } System.out.println(); } } 這里給出一個實現(xiàn)了BeanPostProcessor的類,目的是為了看出postProcessAfterInitialization、postProcessBeforeInitialization調(diào)用的時間點。 /** * 完成bean實例化、配置以及其他初始化方法前后要添加一些自己邏輯處理則要實現(xiàn)接口BeanPostProcessor */ @Component public class MyBeanPostProcessor implements BeanPostProcessor { public MyBeanPostProcessor() { super(); System.out.println("【MyBeanPostProcessor】BeanPostProcessor實現(xiàn)類的構(gòu)造函數(shù)"); } // 實例化、依賴注入完畢,在調(diào)用顯示的初始化之前完成一些定制的業(yè)務(wù) @Override public Object postProcessAfterInitialization(Object arg0, String arg1) throws BeansException { if (arg0.getClass() == TestBeanA.class || arg0.getClass() == TestBeanB.class) { System.out .println("【BeanPostProcessor.postProcessAfterInitialization】來自MyBeanPostProcessor,beanName:" + arg1); } return arg0; } // 實例化、依賴注入、初始化后完成一些定制的業(yè)務(wù) @Override public Object postProcessBeforeInitialization(Object arg0, String arg1) throws BeansException { if (arg0.getClass() == TestBeanA.class || arg0.getClass() == TestBeanB.class) { System.out .println("【BeanPostProcessor.postProcessBeforeInitialization】來自MyBeanPostProcessor,beanName:" + arg1); } return arg0; } }
這里給出繼承了InstantiationAwareBeanPostProcessorAdapter的子類,目的是為了看出postProcessBeforeInitialization、postProcessAfterInitialization、postProcessPropertyValues被調(diào)用的時間點。
/** * 適配器類,基類是BeanPostProcessor的實現(xiàn)類 */ @Component public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter { public MyInstantiationAwareBeanPostProcessor() { super(); System.out .println("【MyInstantiationAwareBeanPostProcessor】InstantiationAwareBeanPostProcessorAdapter實現(xiàn)類的構(gòu)造函數(shù)"); } // 接口方法、實例化Bean之前調(diào)用 @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean.getClass() == TestBeanA.class || bean.getClass() == TestBeanB.class) { System.out .println("【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:" + beanName); } return bean; } // 接口方法、實例化Bean之后調(diào)用 @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean.getClass() == TestBeanA.class || bean.getClass() == TestBeanB.class) { System.out .println("【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:" + beanName); } return bean; } // 接口方法、設(shè)置某個屬性時調(diào)用 @Override public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { if (bean.getClass() == TestBeanA.class || bean.getClass() == TestBeanB.class) { System.out .println("【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】來自MyInstantiationAwareBeanPostProcessor,beanName:" + beanName); } return pvs; }
這個就牛逼了,直接交給applicationContext.xml注入并且實現(xiàn)了BeanFactoryAware, BeanNameAware,InitializingBean,DisposableBean四個接口類,目的是為了清晰的看出以下好幾個接口被調(diào)用的時間點。
public class TestBeanA implements BeanFactoryAware, BeanNameAware, InitializingBean, DisposableBean { private String name; private String address; private int phone; private BeanFactory beanFactory; private String beanName; @PostConstruct public void init() { System.out.println("【TestBeanA.@PostConstruct】"); } public TestBeanA() { System.out.println("【TestBeanA.默認(rèn)構(gòu)造器】"); } public TestBeanA(String name) { System.out.println("【TestBeanA.帶參構(gòu)造器】"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public int getPhone() { return phone; } public void setPhone(int phone) { this.phone = phone; } @Override public String toString() { return "TestBeanA [address=" + address + ", name=" + name + ", phone=" + phone + "]"; } // 這是BeanFactoryAware接口方法 @Override public void setBeanFactory(BeanFactory arg0) throws BeansException { System.out .println("【BeanFactoryAware.setBeanFactory】來自TestBeanA"); this.beanFactory = arg0; } // 這是BeanNameAware接口方法 @Override public void setBeanName(String arg0) { System.out.println("【BeanNameAware.setBeanName】來自TestBeanA"); this.beanName = arg0; } // 這是InitializingBean接口方法 @Override public void afterPropertiesSet() throws Exception { System.out .println("【InitializingBean.afterPropertiesSet】來自TestBeanA"); } // 這是DiposibleBean接口方法 @Override public void destroy() throws Exception { System.out.println("【DiposibleBean.destory】來自TestBeanA"); } // 通過的init-method屬性指定的初始化方法 public void myInit() { System.out.println("【TestBeanA.myInit】"); } // 通過 的destroy-method屬性指定的初始化方法 public void myDestory() { System.out.println("【TestBeanA.destroy-method】"); } }
TestBeanB的作用比較簡單,為了看出內(nèi)部數(shù)據(jù)成員有其他容器Bean的時候Spring是如何加載bean的。
@Component public class TestBeanB { @Autowired private TestBeanA testBeanA; public TestBeanB() { System.out.println("【TestBeanB.默認(rèn)構(gòu)造器】"); } }
這個是啟動類。
@SpringBootApplication @ImportResource(locations = {"classpath:applicationContext.xml"}) public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
雖然使用的是SpringBoot,這里還使用xml是為了看看init-method和destroy-method的調(diào)用時間。
很長很長的代碼算是都給出來了,接下來看下運行后給出的結(jié)果
【BeanFactoryPostProcessor】實現(xiàn)類postProcessBeanFactory的構(gòu)造函數(shù) 【BeanFactoryPostProcessor.postProcessBeanFactory】,來自MyBeanFactoryPostProcessor 【MyBeanPostProcessor】BeanPostProcessor實現(xiàn)類的構(gòu)造函數(shù) 【MyInstantiationAwareBeanPostProcessor】InstantiationAwareBeanPostProcessorAdapter實現(xiàn)類的構(gòu)造函數(shù) 【TestBeanB.默認(rèn)構(gòu)造器】 【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB 【TestBeanA.默認(rèn)構(gòu)造器】 【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA 【BeanNameAware.setBeanName】來自TestBeanA 【BeanFactoryAware.setBeanFactory】來自TestBeanA 【BeanPostProcessor.postProcessBeforeInitialization】來自MyBeanPostProcessor,beanName:testBeanA 【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA 【TestBeanA.@PostConstruct】 【InitializingBean.afterPropertiesSet】來自TestBeanA 【TestBeanA.myInit】 【BeanPostProcessor.postProcessAfterInitialization】來自MyBeanPostProcessor,beanName:testBeanA 【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA 【BeanPostProcessor.postProcessBeforeInitialization】來自MyBeanPostProcessor,beanName:testBeanB 【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB 【BeanPostProcessor.postProcessAfterInitialization】來自MyBeanPostProcessor,beanName:testBeanB 【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB 【DiposibleBean.destory】來自TestBeanA 【TestBeanA.destroy-method】
貌似又是一段看完頭暈?zāi)X脹的惡心代碼,不過不方不方,直接進(jìn)入分析階段,跟著分析入手就簡單多了。
通過結(jié)果分析首先從
【BeanFactoryPostProcessor】實現(xiàn)類postProcessBeanFactory的構(gòu)造函數(shù) 【BeanFactoryPostProcessor.postProcessBeanFactory】,來自MyBeanFactoryPostProcessor 【MyBeanPostProcessor】BeanPostProcessor實現(xiàn)類的構(gòu)造函數(shù) 【MyInstantiationAwareBeanPostProcessor】InstantiationAwareBeanPostProcessorAdapter實現(xiàn)類的構(gòu)造函數(shù)
可以看出執(zhí)行順序是:
調(diào)用postProcessBeanFactory實現(xiàn)類的構(gòu)造函數(shù)
BeanFactoryPostProcessor是bean工廠的處理器
調(diào)用postProcessBeanFactory實現(xiàn)類的postProcessBeanFactory實現(xiàn)函數(shù)
postProcessBeanFactory函數(shù)允許我們在工廠里所有的bean被加載進(jìn)來后但是還沒初始化前,對所有bean的屬性進(jìn)行修改也可以add屬性值
調(diào)用BeanPostProcessor實現(xiàn)類的構(gòu)造函數(shù)
完成bean實例化、配置以及其他初始化方法前后要添加一些自己邏輯處理則要實現(xiàn)接口BeanPostProcessor
調(diào)用InstantiationAwareBeanPostProcessorAdapter實現(xiàn)類的構(gòu)造函數(shù)
適配器類,基類是BeanPostProcessor的實現(xiàn)類
再從
【TestBeanB.默認(rèn)構(gòu)造器】 【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB
可以看到,此處spring容器先掃描到了TestBeanB,因此調(diào)用順序是
TestBeanB的默認(rèn)構(gòu)造器【無參構(gòu)造器】
調(diào)用InstantiationAwareBeanPostProcessorAdapter實現(xiàn)類的postProcessPropertyValues接口
postProcessPropertyValues在接口方法、設(shè)置某個屬性時調(diào)用,通過實驗看到實例化一個Bean的時候也會調(diào)用該接口方法
之后實例化TestBeanB的時候發(fā)現(xiàn)內(nèi)部注入了TestBeanA,因此Spring轉(zhuǎn)而實例化TestBeanA。
接下來看到的是TestBeanA的實例化過程中調(diào)用的順序
【TestBeanA.默認(rèn)構(gòu)造器】 【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA 【BeanNameAware.setBeanName】來自TestBeanA 【BeanFactoryAware.setBeanFactory】來自TestBeanA 【BeanPostProcessor.postProcessBeforeInitialization】來自MyBeanPostProcessor,beanName:testBeanA 【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA 【TestBeanA.@PostConstruct】 【InitializingBean.afterPropertiesSet】來自TestBeanA 【TestBeanA.myInit】 【BeanPostProcessor.postProcessAfterInitialization】來自MyBeanPostProcessor,beanName:testBeanA 【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA
調(diào)用了TestBeanA的默認(rèn)構(gòu)造器
調(diào)用InstantiationAwareBeanPostProcessorAdapter實現(xiàn)類的postProcessPropertyValues接口
調(diào)用BeanNameAware的setBeanName接口
可以從源碼看到TestBeanA實現(xiàn)了接口BeanNameAware
調(diào)用BeanFactoryAware的setBeanFactory接口
可以從源碼看到TestBeanA實現(xiàn)了接口BeanFactoryAware
調(diào)用BeanPostProcessor的postProcessBeforeInitialization接口
調(diào)用InstantiationAwareBeanPostProcessorAdapter的postProcessBeforeInitialization接口
調(diào)用TestBeanA中注解了@PostConstruct的函數(shù)
調(diào)用了InitializingBean的afterPropertiesSet接口
可以從源碼看到TestBeanA實現(xiàn)了接口InitializingBean
調(diào)用了TestBeanA的myInit接口
可以看到該init-method接口是在applicationContext中init-method配置上的
調(diào)用BeanPostProcessor實現(xiàn)類的postProcessAfterInitialization接口
調(diào)用InstantiationAwareBeanPostProcessorAdapter子類的postProcessAfterInitialization接口
等TestBeanA實例化結(jié)束后,則繼續(xù)TestBeanB的實例化路程
【BeanPostProcessor.postProcessBeforeInitialization】來自MyBeanPostProcessor,beanName:testBeanB 【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB 【BeanPostProcessor.postProcessAfterInitialization】來自MyBeanPostProcessor,beanName:testBeanB 【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB
調(diào)用BeanPostProcessor實現(xiàn)類的postProcessBeforeInitialization接口
調(diào)用InstantiationAwareBeanPostProcessorAdapter子類的postProcessBeforeInitialization接口
調(diào)用BeanPostProcessor實現(xiàn)類的postProcessAfterInitialization接口
調(diào)用InstantiationAwareBeanPostProcessorAdapter子類的postProcessAfterInitialization接口
最后
【DiposibleBean.destory】來自TestBeanA 【TestBeanA.destroy-method】
調(diào)用DiposibleBean實現(xiàn)類的destory接口
TestBeanA實現(xiàn)了DiposibleBean接口,實現(xiàn)了destroy接口
調(diào)用TestBeanA的myDestory函數(shù)
可以看到該myDestory接口是在applicationContext中destroy-method配置上的。最終總結(jié)
【超重點,面試回答模板,老牛逼了】
如果有bean實現(xiàn)了BeanFactoryPostProcessor接口類,則會實例化該bean,并且調(diào)用默認(rèn)構(gòu)造器,然后調(diào)用postProcessBeanFactory接口
如果有bean實現(xiàn)了BeanPostProcessor接口類,則會先實例化該bean,同樣調(diào)用默認(rèn)構(gòu)造器
如果有bean繼承了InstantiationAwareBeanPostProcessorAdapter類,則會先實例化該bean,同樣調(diào)用默認(rèn)構(gòu)造器
之后真正進(jìn)入一個bean的生命周期過程
先調(diào)用bean的默認(rèn)構(gòu)造函數(shù)
如果有bean繼承了InstantiationAwareBeanPostProcessorAdapter類,此刻會調(diào)用postProcessPropertyValues函數(shù)
如果這個bean已經(jīng)實現(xiàn)了BeanNameAware接口,會調(diào)用它實現(xiàn)的setBeanName方法,此處傳遞的就是applicationContext.xml配置文件中Bean的id值
如果這個bean已經(jīng)實現(xiàn)了BeanFactoryAware接口,會調(diào)用它實現(xiàn)的setBeanFactory,傳遞的是Spring工廠自身
如果存在其他bean實現(xiàn)了BeanPostProcessor接口,將會調(diào)用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor經(jīng)常被用作是Bean內(nèi)容的更改,并且由于這個是在Bean初始化結(jié)束時調(diào)用那個的方法,也可以被應(yīng)用于內(nèi)存或緩存技術(shù);
如果存在其他bean繼承了InstantiationAwareBeanPostProcessorAdapter類,則會調(diào)用postProcessBeforeInitialization接口
如果這個bean中有函數(shù)加了@PostConstruct注解,則該函數(shù)會在此刻被調(diào)用
如果這個bean實現(xiàn)了InitializingBean接口重寫了afterPropertiesSet方法,該方法會在此刻被調(diào)用
如果這個bean在Spring配置文件中配置了init-method屬性,則會自動調(diào)用其配置的初始化方法。
如果存在其他bean實現(xiàn)了BeanPostProcessor接口,將會調(diào)用postProcessAfterInitialization(Object obj, String s)方法
如果存在其他bean繼承了InstantiationAwareBeanPostProcessorAdapter類,則會調(diào)用postProcessAfterInitialization接口
走到這一步以后就可以應(yīng)用這個Bean了,而這個Bean是一個Singleton的,雖然在Spring配置文件中也可以配置非Singleton,這里不做贅述。
走入銷毀階段
當(dāng)bean不再需要時,會經(jīng)過清理階段,如果這個bean實現(xiàn)了DisposableBean接口,會調(diào)用其實現(xiàn)的destroy()方法;
如果這個bean的applicationContext.xml配置中配置了destroy-method屬性,會自動調(diào)用其配置的銷毀方法。
Java源碼分析、go語言應(yīng)用、微服務(wù),更多干貨歡迎關(guān)注公眾號:
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/74697.html
摘要:例如資源的獲取,支持多種消息例如的支持,對多了工具級別的支持等待。最上面的知道吧我就不講了。生命周期事件回調(diào)等。他支持不同信息源頭,支持工具類,支持層級容器,支持訪問文件資源,支持事件發(fā)布通知,支持接口回調(diào)等等。 廣義的 IOC IoC(Inversion of Control) 控制反轉(zhuǎn),即不用打電話過來,我們會打給你。 兩種實現(xiàn): 依賴查找(DL)和依賴注入(DI)。 IOC 和...
摘要:本文是容器源碼分析系列文章的第一篇文章,將會著重介紹的一些使用方法和特性,為后續(xù)的源碼分析文章做鋪墊。我們可以通過這兩個別名獲取到這個實例,比如下面的測試代碼測試結(jié)果如下本小節(jié),我們來了解一下這個特性。 1. 簡介 Spring 是一個輕量級的企業(yè)級應(yīng)用開發(fā)框架,于 2004 年由 Rod Johnson 發(fā)布了 1.0 版本。經(jīng)過十幾年的迭代,現(xiàn)在的 Spring 框架已經(jīng)非常成熟了...
摘要:實例化時,發(fā)現(xiàn)又依賴于。一些緩存的介紹在進(jìn)行源碼分析前,我們先來看一組緩存的定義??墒强赐暝创a后,我們似乎仍然不知道這些源碼是如何解決循環(huán)依賴問題的。 1. 簡介 本文,我們來看一下 Spring 是如何解決循環(huán)依賴問題的。在本篇文章中,我會首先向大家介紹一下什么是循環(huán)依賴。然后,進(jìn)入源碼分析階段。為了更好的說明 Spring 解決循環(huán)依賴的辦法,我將會從獲取 bean 的方法getB...
摘要:依賴注入是向某個類或方法注入一個值,其中所用到的原理就是控制反轉(zhuǎn)。但發(fā)現(xiàn)更多時間是在調(diào)和的源碼。里面就是從中取出這個,完成控制反轉(zhuǎn)的??刂品崔D(zhuǎn)的優(yōu)點最后來以我個人觀點談?wù)効刂品崔D(zhuǎn)的優(yōu)點吧??刂品崔D(zhuǎn)為了降低項目耦合,提高延伸性。 本章開始來學(xué)習(xí)下Spring的源碼,看看Spring框架最核心、最常用的功能是怎么實現(xiàn)的。網(wǎng)上介紹Spring,說源碼的文章,大多數(shù)都是生搬硬推,都是直接看來的...
摘要:在上文中,我實現(xiàn)了一個很簡單的和容器。比如,我們所熟悉的就是在這里將切面邏輯織入相關(guān)中的。初始化的工作算是結(jié)束了,此時處于就緒狀態(tài),等待外部程序的調(diào)用。其中動態(tài)代理只能代理實現(xiàn)了接口的對象,而動態(tài)代理則無此限制。 1. 背景 本文承接上文,來繼續(xù)說說 IOC 和 AOP 的仿寫。在上文中,我實現(xiàn)了一個很簡單的 IOC 和 AOP 容器。上文實現(xiàn)的 IOC 和 AOP 功能很單一,且 I...
閱讀 931·2021-11-08 13:22
閱讀 2856·2021-09-29 09:45
閱讀 2835·2021-09-09 11:52
閱讀 2269·2019-08-30 13:20
閱讀 3751·2019-08-29 13:28
閱讀 1372·2019-08-29 12:32
閱讀 2732·2019-08-29 11:10
閱讀 1653·2019-08-26 13:34