Spring加載bean的時候構造函數何時調用、@PostConstruct何時調用、實現了BeanPostProcessor接口的bean中的postProcessAfterInitialization和postProcessBeforeInitialization何時調用?你是否清楚呢?若是清楚的話能夠直接忽略該篇文章!!!
最近來了幾個新人,被問了一個和bean生命週期相關的一個知識點,解決新人的問題後本身再寫了一個demo,目的是爲了清晰的描述整個bean的生命週期。git
注意注意,如下demo有五個類,可能會引發部分人不適,建議能夠直接跳到最後看 最終總結,或者本身下載源碼運行下。
demo地址: https://github.com/wiatingpub...
首先給出一個實現了BeanFactoryPostProcessor的類,目的是爲了比較清晰的看出postProcessBeanFactory接口被調用的時間點。github
/** * BeanFactoryPostProcessor是bean工廠的處理器 */ @Component public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { public MyBeanFactoryPostProcessor() { super(); System.out.println("【BeanFactoryPostProcessor】實現類postProcessBeanFactory的構造函數"); } // 容許咱們在工廠裏全部的bean被加載進來後可是還沒初始化前,對全部bean的屬性進行修改也能夠add屬性值,該操做在對應bean的構造函數執行前 @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0) throws BeansException { System.out .println("【BeanFactoryPostProcessor.postProcessBeanFactory】,來自MyBeanFactoryPostProcessor"); //獲取到Spring中全部的beanName String[] beanStr = arg0.getBeanDefinitionNames(); //循環打印 for (String beanName : beanStr) { System.out.print("bean name:" + beanName + ";"); } System.out.println(); } } 這裏給出一個實現了BeanPostProcessor的類,目的是爲了看出postProcessAfterInitialization、postProcessBeforeInitialization調用的時間點。 /** * 完成bean實例化、配置以及其餘初始化方法先後要添加一些本身邏輯處理則要實現接口BeanPostProcessor */ @Component public class MyBeanPostProcessor implements BeanPostProcessor { public MyBeanPostProcessor() { super(); System.out.println("【MyBeanPostProcessor】BeanPostProcessor實現類的構造函數"); } // 實例化、依賴注入完畢,在調用顯示的初始化以前完成一些定製的業務 @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; } // 實例化、依賴注入、初始化後完成一些定製的業務 @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被調用的時間點。面試
/** * 適配器類,基類是BeanPostProcessor的實現類 */ @Component public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter { public MyInstantiationAwareBeanPostProcessor() { super(); System.out .println("【MyInstantiationAwareBeanPostProcessor】InstantiationAwareBeanPostProcessorAdapter實現類的構造函數"); } // 接口方法、實例化Bean以前調用 @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以後調用 @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; } // 接口方法、設置某個屬性時調用 @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注入而且實現了BeanFactoryAware, BeanNameAware,InitializingBean,DisposableBean四個接口類,目的是爲了清晰的看出如下好幾個接口被調用的時間點。spring
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.默認構造器】"); } public TestBeanA(String name) { System.out.println("【TestBeanA.帶參構造器】"); } 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"); } // 經過<bean>的init-method屬性指定的初始化方法 public void myInit() { System.out.println("【TestBeanA.myInit】"); } // 經過<bean>的destroy-method屬性指定的初始化方法 public void myDestory() { System.out.println("【TestBeanA.destroy-method】"); } }
TestBeanB的做用比較簡單,爲了看出內部數據成員有其餘容器Bean的時候Spring是如何加載bean的。編程
@Component public class TestBeanB { @Autowired private TestBeanA testBeanA; public TestBeanB() { System.out.println("【TestBeanB.默認構造器】"); } }
這個是啓動類。緩存
@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的調用時間。微信
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="testBeanA" class="com.example.demo.bean.TestBeanA" init-method="myInit" destroy-method="myDestory"> <property name="name" value="關注微信公衆號 飯說編程"/> </bean> </beans>
很長很長的代碼算是都給出來了,接下來看下運行後給出的結果app
【BeanFactoryPostProcessor】實現類postProcessBeanFactory的構造函數 【BeanFactoryPostProcessor.postProcessBeanFactory】,來自MyBeanFactoryPostProcessor 【MyBeanPostProcessor】BeanPostProcessor實現類的構造函數 【MyInstantiationAwareBeanPostProcessor】InstantiationAwareBeanPostProcessorAdapter實現類的構造函數 【TestBeanB.默認構造器】 【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB 【TestBeanA.默認構造器】 【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】
貌似又是一段看完頭暈腦脹的噁心代碼,不過不方不方,直接進入分析階段,跟着分析入手就簡單多了。ide
首先從函數
【BeanFactoryPostProcessor】實現類postProcessBeanFactory的構造函數 【BeanFactoryPostProcessor.postProcessBeanFactory】,來自MyBeanFactoryPostProcessor 【MyBeanPostProcessor】BeanPostProcessor實現類的構造函數 【MyInstantiationAwareBeanPostProcessor】InstantiationAwareBeanPostProcessorAdapter實現類的構造函數
能夠看出執行順序是:
BeanFactoryPostProcessor是bean工廠的處理器
postProcessBeanFactory函數容許咱們在工廠裏全部的bean被加載進來後可是還沒初始化前,對全部bean的屬性進行修改也能夠add屬性值
完成bean實例化、配置以及其餘初始化方法先後要添加一些本身邏輯處理則要實現接口BeanPostProcessor
適配器類,基類是BeanPostProcessor的實現類
再從
【TestBeanB.默認構造器】 【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB
能夠看到,此處spring容器先掃描到了TestBeanB,所以調用順序是
postProcessPropertyValues在接口方法、設置某個屬性時調用,經過實驗看到實例化一個Bean的時候也會調用該接口方法
以後實例化TestBeanB的時候發現內部注入了TestBeanA,所以Spring轉而實例化TestBeanA。
接下來看到的是TestBeanA的實例化過程當中調用的順序
【TestBeanA.默認構造器】 【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
能夠從源碼看到TestBeanA實現了接口BeanNameAware
能夠從源碼看到TestBeanA實現了接口BeanFactoryAware
能夠從源碼看到TestBeanA實現了接口InitializingBean
能夠看到該init-method接口是在applicationContext中init-method配置上的
等TestBeanA實例化結束後,則繼續TestBeanB的實例化路程
【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】
TestBeanA實現了DiposibleBean接口,實現了destroy接口
能夠看到該myDestory接口是在applicationContext中destroy-method配置上的。
【超重點,面試回答模板,老牛逼了】
以後真正進入一個bean的生命週期過程
走到這一步之後就能夠應用這個Bean了,而這個Bean是一個Singleton的,雖然在Spring配置文件中也能夠配置非Singleton,這裏不作贅述。
走入銷燬階段
Java源碼分析、go語言應用、微服務,更多幹貨歡迎關注公衆號: