Sping中bean的生命週期(代碼展示)

一個Bean從生到滅要經歷很多過程,總體分爲定義、實例化、屬性賦值(依賴注入)、初始化、生存期、銷燬。

如下圖,是個概括圖,後面重點介紹Bean的定義、初始化、銷燬過程:

下面是一個細化的Bean生命週期圖: 

一、Bean的定義

Bean的定義過程其實就是如何正確地將 Bean 裝配到 IoC 容器中。

  1. Spring通過我們的配置,如@ComponentScan定義的掃描路徑去找到帶有@Component的類,完成資源定位的過程
  2. 一旦找到了資源,那麼它就開始解析,並且將定義的信息在BeanDefinition的實現類中保存起來 。注意,此時還沒有初始Bean,也就沒有Bean實例,它有的僅僅是 Bean 定義。
  3. 然後就會把 Bean 定義發佈到 Spring IoC 容器中。此時,IoC 容器也只有 Bean 的定義,還是沒有 Bean的實例生成。

 BeanDefinition的實現類可以保存這個bean的構造函數參數、bean的Scope範圍、是否是延遲初始化LazyInit、是否是Singleton等信息。

二、Bean的初始化

上面Bean的定義只是一個資源定位並將 Bean 的定義發佈到 IoC 容器的過程,還沒有 Bean 實例的生成,更沒有完成依賴注入。在默認的情況下,spring 會繼續去完成 Bean 實例化和依賴注入,這樣從 IoC 容器中就可以得到一個依賴注入完成的 Bean 但是,有些 Bean 會受到變化因 的影響,這時我們希望是取出 Bean 的時候完成初始化和依賴注入,換句話說就是讓那些 Bean 只是將定義發佈到 IoC 容器而不做實例化和依賴注入,當我們取出來的時候才做初始化和依賴注入等操作,也就是延遲初始化Bean。@ComponentScan 中還有一個配置項 lazyInit ,只可以配 Boolean 值,且默認值爲 false ,也就是默認不進行延遲初始化,因此在默認的情況下 Spring 會對 Bea 進行實例化和依賴注入對應的屬性值。

 

如果僅僅是實例化和依賴注入還是比較簡單的,還不能完成進行自定義的要求,爲了完成依賴注入的功能 Spring 在完成依賴注入之後 ,還提供了 列的接口和配置來完 Bean 初始化的過程,如上面的詳細初始化過程。
 

三、代碼驗證

我們還是用人類要喫飯的關係類說明Bean的生命週期。先實現Person和Food兩個接口: 

public interface Person {
    public void live();

    public void setFood(Food food);
}
public interface Food {
    public void eat();
}

接着編寫上面兩個接口的實現類: 

@Component
public class Apple implements Food {
    @Override
    public void eat() {
        System.out.println("我是蘋果,喫我吧");
    }
}
public class ZhangSan implements Person, BeanNameAware, BeanFactoryAware,
        ApplicationContextAware, InitializingBean, DisposableBean {

    private Food food = null;

    /**
     * 來自Person接口
     */
    @Override
    public void live() {
        this.food.eat();
    }

    /**
     * 來自Person接口
     */
    @Override
    public void setFood(Food food) {
        System.out.println("設置 food !");
        this.food = food;
    }

    /**
     * 來自BeanNameAware接口
     */
    @Override
    public void setBeanName(String beanName) {
        System.out.println("【" + this.getClass().getSimpleName() + "】調用BeanNameAware的setBeanName");
    }

    /**
     * 來自BeanFactoryAware接口
     */
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("【" + this.getClass().getSimpleName() + "】調用BeanFactoryAware的setBeanFactory");
    }

    /**
     * 來自BApplicationContextAware接口
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("【" + this.getClass().getSimpleName() + "】調用ApplicationContextAware的setApplicationContext");
    }

    /**
     * 來自InitializingBean接口
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("【" + this.getClass().getSimpleName() + "】調用InitializingBean的afterPropertiesSet");
    }

    @PostConstruct
    public void init() {
        System.out.println("【" + this.getClass().getSimpleName() + "】註解@Postconstruct定義的自定義初始化方法");
    }

    @PreDestroy
    public void destroy1() {
        System.out.println("【" + this.getClass().getSimpleName() + "】註解@PreDestroy定義的自定義銷燬方法");
    }

    /**
     * 來自DisposableBean接口
     */
    @Override
    public void destroy() throws Exception {
        System.out.println("【" + this.getClass().getSimpleName() + "】調用DisposableBean方法");
    }
}

上面我們讓ZhangSan實現了多個初始化需要的接口,並實現了相應的方法,來完成ZhangSan這個bean的初始化處理,爲了說明自定義初始化方法,我們使用@PostConstruct註解增加了自定義初始化過程,爲了說明自定義銷燬方法我們使用@PreDestroy增加了自定義銷燬過程,另外爲了說明BeanPostProcessor接口是針對全部bean的,下面實現了這個接口:

public class BeanPostProcessorExample implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor調用postProcessBeforeInitialization參數【" + bean.getClass().getSimpleName()+"】【" + beanName + "】");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor調用postProcessAfterInitialization參數【" + bean.getClass().getSimpleName()+"】【" + beanName + "】");
        return bean;
    }
}

然後我們用一個類聚合下上面的bean: 

@Configuration
public class Config {

    @Bean
    public ZhangSan initZhangSan(){
        ZhangSan zhangSan = new ZhangSan();
        zhangSan.setFood(new Apple());
        return zhangSan;
    }

    @Bean
    public BeanPostProcessorExample initExample(){
        return new BeanPostProcessorExample();
    }
}

測試類: 

@SpringBootTest
class GfdemoApplicationTests {

    @Test
    void contextLoads() {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
        ctx.close();
    }

}

結果:

BeanPostProcessor調用postProcessBeforeInitialization參數【Apple】【apple】
BeanPostProcessor調用postProcessAfterInitialization參數【Apple】【apple】
設置 food !
【ZhangSan】調用BeanNameAware的setBeanName
【ZhangSan】調用BeanFactoryAware的setBeanFactory
【ZhangSan】調用ApplicationContextAware的setApplicationContext
BeanPostProcessor調用postProcessBeforeInitialization參數【ZhangSan】【initZhangSan】
【ZhangSan】註解@Postconstruct定義的自定義初始化方法
【ZhangSan】調用InitializingBean的afterPropertiesSet
BeanPostProcessor調用postProcessAfterInitialization參數【ZhangSan】【initZhangSan】
【ZhangSan】註解@PreDestroy定義的自定義銷燬方法
【ZhangSan】調用DisposableBean方法

可以看出bean的生命週期流程是按照上面的圖進行的,另外也可以看出BeanPostProcessor接口是針對全部bean的,在初始化Apple和ZhangSan的時候都有執行。

 

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