關於Spring中Bean的生命週期

1、Spring生命週期

  • 所謂生命週期就是一個對象從初始化到銷燬的過程,在Spring容器中bean的生命週期可以總結爲:

    1. 初始化(實例化);
    2. 屬性注入(我們平時new對象還不是一樣要set屬性);
    3. 如果bean實現BeanNameAuthorware接口,則執行setBeanName的方法(作用是給bean設置一個獨有的id方面我們獲取實例並使用);
    4. 如果bean實現了BeanFactoryAware接口,spring將會調用setBeanFactory()方法將BeanFactory容器傳入;
    5. 如果bean實現了ApplicationContextAware接口,spring將調用setApplication()方法,將bean所在的應用上下文的引用傳入進來;
    6. 如果bean實現了BeanPostProcessor接口,Spring將調用所有bean的postProcessBeforeInitialization()方法;
    7. 如果bean實現了InitializingBean接口,spring將調用它們的afterPropertiesSet()方法,類似的,如果bean使用init-method聲明瞭初始化方法,該方法也會調用,或者使用註解@PostConstruct都一樣的效果。
    8. 跟第6條對應,同樣的接口 ,調用所有bean的postProcessAfterInitialization()方法
    9. 調用@PreDestroy標註的方法;
    10. 如果bean實現接DisposableBean接口,會調用它的destroy()方法
  • 圖解
    在這裏插入圖片描述
    在這裏安利一本書:spring實戰第四版,這個圖就跟書上的一模一樣,看完了個人感覺對於spring的理解非常到位(個人感覺前面的幾章寫得非常好)

2、演示bean生命週期

  • 搭建一個springboot項目(spring或者springboot都可以演示,主要是用了springboot就不會再想玩spring了)
  • 寫三個類:
    1. TestBean:
package com.example.demo.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import javax.annotation.PreDestroy;


public class TestBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("執行了:setBeanFactory");
    }

    @Override
    public void setBeanName(String s) {
        System.out.println("執行了:setBeanName");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("執行了:destroy");
    }
    @PreDestroy
    public void annodestroy(){
        System.out.println("執行了:@PreDestroy標註的方法");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("執行了:afterPropertiesSet");
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("執行了:setApplicationContext");
    }
}
	

太長了?其實大部分都不用看,只用看實現了什麼接口,對照着圖看就好了,實際自己寫起來理解也很方便。

  1. TestPostProcessorBean:
package com.example.demo.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;


public class TestPostProcessorBean implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("執行了:postProcessBeforeInitialization");
        return null;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("執行了:postProcessAfterInitialization");
        return null;
    }
}

這裏要注意,BeanPostProcessor接口的兩個方法所有的bean都會執行的,這裏爲什麼要單獨拎出來,BeanPostProcessor類是爲了讓創建其他類的時候進行創建前後的一些操作,如果寫在TestBean上實現的話一般是不會調用postProcessBeforeInitialization()和postProcessAfterInitialization()方法的。原因就是,在容器初始化定義的bean創建之前,容器會自己去查找所有的BeanPostProcessor進行創建自定義的類,由於是實現了BeanPostProcessor接口,因此這時候會進行BeanPostProcessor的創建和註冊,源碼中,在註冊BeanPostProcessor會進行getBean操作,即創建自定義的bean。由於默認的是單例模式,因此後面再次進行獲取就不會再次調用postProcessBeforeInitialization()和postProcessAfterInitialization()方法,因爲已經放入了spring緩存,直接獲取,不需要實例,因此沒有調用。

  1. TestConfig:
package com.example.demo.config;

import com.example.demo.bean.TestBean;
import com.example.demo.bean.TestPostProcessorBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class TestConfig {
   @Bean("TestBean")
   public TestBean getTestBean(){
       return new TestBean();
   }

   @Bean("TestPostProcessorBean")
   public TestPostProcessorBean getPostProcessorBean(){
       return new TestPostProcessorBean();
   }
}

3、代碼測試

package com.example.demo;

import com.example.demo.bean.TestBean;
import com.example.demo.config.TestConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class TestMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ap=new AnnotationConfigApplicationContext(TestConfig.class);
        ap.getBean("TestBean", TestBean.class);
        ap.close();
    }
}

結果:
在這裏插入圖片描述
注意main方法要記得銷燬上下文哦,不然destroy方法是走不到的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章