Spring Bean的生命週期是Spring面試熱點問題。這個問題即考察對Spring的微觀瞭解,又考察對Spring的宏觀認識,想要答好並不容易!本文但願可以從源碼角度入手,幫助面試者完全搞定Spring Bean的生命週期,如下部份內容參考Spring學習筆記,感興趣的朋友也能夠閱讀一下!面試
在面試中,咱們常常會被問到一個問題,就是SpringBean的生命週期。用大白話說,就是說其在創造到銷燬按順序調用了什麼方法,在我剛開始學了,通常就是對着標準答案去硬背,徹底不瞭解其意思,也十分容易忘記。spring
流程圖以下app
這樣看上去十分的複雜,記住也很容易忘掉。ide
因此,我下面會用代碼的方式一步步來模擬SpringBean的工做流程,作到深刻了解,這樣就不會再次忘記這個知識點了。post
既然都說Bean對象Bean對象,那麼SpringBean天然也是一個對象了,咱們用一個簡單的對象來講明,那麼要建立對象就須要有構造方法,對象還會有它的屬性跟get、set方法。學習
private String field; public SpringBean() { System.out.println("SpringBean 構造方法"); } public String getField() { System.out.println("SpringBean get方法"); return field; } public void setField(String field) { System.out.println("SpringBean set方法"); this.field = field; }
衆所周知要建立一個SpringBean的話還要在配置文件裏去聲明這個Beam,固然也能夠用註解的方式。this
<bean class="SpringBean"> <property name="field" value="test" /> </bean>
而後咱們去初始化這個容器看看,運行結果是什麼code
public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); }
這裏咱們能夠看到當咱們在容器裏面加載bean的時候,它會依次調用構造方法和set方法,這兩步我相信大部分人都知道。可是除此以外咱們想想,咱們的Spring它是否還幹了別的事情,咱們接下來看一下。xml
若是這個Bean它實現了一些Aware接口的話,它就會注入和bean容器基礎屬性層面相關的信息。好比實現了BeanNameAware接口,咱們要重寫它的setBeanName方法,在配置文件中把這個Bean的id設置一下對象
public void setBeanName(String s) { System.out.println("setBeanName:"+s); }
<bean id="BeanName" class="SpringBean"> <property name="field" value="test" /> </bean>
運行一下看會發生什麼
剩下的BeanFactoryAware和ApplicationContextAware接口同理,咱們直接看結果
咱們能夠看到先執行的是setBeanFactory方法而後是setApplicationContext方法
下面咱們再建立一個新的Bean,這個Bean是作全局的前置和後置初始化的,也就是咱們看面試題時所說的前置處理器和後置處理器。
這個Bean咱們實現BeanPostProcessor接口
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization"); return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization"); return null; }
千萬不要忘記要在配置文件裏聲明這個Bean
<bean class="SpringProccesserBean"></bean>
而後咱們再運行試試
不出咱們所料,前置方法和後置方法依次在後面運行了,難道這就是Bean的所有了嗎?呵呵,太天真了,若是在Bean中有實現InitializingBean接口,那又是不一樣的說法了。咱們下面除了重寫了afterPropertiesSet方法之外咱們還能夠在bean裏面指定它的init方法。
public void afterPropertiesSet() throws Exception { System.out.println("afterPropertiesSet"); } public void init(){ System.out.println("init"); }
不要忘記配置文件
<bean id="BeanName" class="SpringBean" init-method="init"> <property name="field" value="test" /> </bean>
能夠看到,這兩個方法是夾在前置處理器和後置處理器之間的,先執行的是InitializingBean接口的afterPropertiesSet方法而後是Bean自身的init方法。
至此,一個Bean的初始化環節就完成了,咱們就能夠去使用這個Bean了。
既然是說Bean的生命週期,那固然還有Bean的銷燬流程了,Bean的銷燬流程一共分爲連個步驟,一個步驟是實現銷燬接口DisposableBean,重寫它的銷燬方法destroy,還有一個是Bean自身的destroy方法。
public void destroy() throws Exception { System.out.println("DisposableBean"); } public void des(){ System.out.println("des"); }
記得要在配置文件裏定義
<bean id="BeanName" class="SpringBean" init-method="init" destroy-method="des"> <property name="field" value="test" /> </bean>
這兩個方法會在關閉容易的時候調用,所以咱們調用close方法關閉容器
public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); applicationContext.close(); }
運行結果
咱們看到是先調用DisposableBean接口的destroy方法而後是Bean自身的銷燬方法。
這就是SpringBean的生命週期。
讀者福利:Spring boot學習筆記+面試真題
一、實例化Bean對象
二、設置Bean屬性
三、若是經過各類Aware接口聲明瞭依賴關係,則會注入Bean對容器基礎設施層面的依賴。
Aware接口集體包括BeanNameAware、BeanFactoryAware和ApplicationContextAware
分別注入Bean ID、Bean Factory 和ApplicationContext
四、若是實現了BeanPostProcesser,調用BeanPostProcesser的前置初始化方法postProcessBeforeInitialization
五、若是實現了InitializingBean接口,則會調用afterPropertiesSet方法
六、調用Bean自身定義的init方法
七、調用BeanPostProcesser的後置方法postProcessAfterInitialization
建立完畢
銷燬
八、容器關閉前調用DisposableBean的destroy方法和自身的destroy方法