天天看點

Spring5源碼分析------bean的生命周期(二)

代碼位址

spring02

覺得部落客還可以給個Star

Spring Bean的生命周期

  1. 如何判斷Bean初始化了

    初始化:指的是對象已經建立并且裡面所有的set已經全部執行完畢

    在@Bean中有着initMethod,destoryMethod屬性,他們代表着bean被初始化和銷毀

    具體用法:

    UserEntity.java

package com.entity;


public class UserEntity {

    public UserEntity(){
        System.out.println("UserEntity無參構造...");
    }

    private void initMsg() {
        System.out.println("UserEntity initMsg");
    }

    private void destroyMsg() {
        System.out.println("UserEntity destroyMsg");
    }
}
           

MyConfig.java

@Configuration
@ComponentScan("com.entity")
public class MyConfig {

    @Bean(initMethod = "initMsg",destroyMethod = "destroyMsg")
    public UserEntity userEntity(){
        return new UserEntity();
    }
}
           

Application.java

import com.config.MyConfig;
import com.entity.UserEntity;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Application {
    public static void main(String[] args) {
//        ApplicationContext
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        UserEntity userEntity = annotationConfigApplicationContext.getBean("userEntity", UserEntity.class);
    }
}
           

運作結果:

Spring5源碼分析------bean的生命周期(二)

我們會發現"UserEntity destroyMsg"并未被列印出來,那是因為容器并未被銷毀,是以我們可以自己關閉容器,清除裡面的bean

Application.java

import com.config.MyConfig;
import com.entity.UserEntity;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Application {
    public static void main(String[] args) {
//        ApplicationContext
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        UserEntity userEntity = annotationConfigApplicationContext.getBean("userEntity", UserEntity.class);
        annotationConfigApplicationContext.close();
    }
}
           
Spring5源碼分析------bean的生命周期(二)

其實判斷的方法還有很多種,比如

  1. 實作接口InitializingBean, DisposableBean

    建立BookEntity.java

package com.entity;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class BookEntity implements InitializingBean, DisposableBean {
    @Override
    public void destroy() throws Exception {
        System.out.println("BookEntity 銷毀前執行");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("BookEntity執行個體化完成");
    }
}
           
Spring5源碼分析------bean的生命周期(二)

2. JSR250

建立PayEntity.java

package com.entity;

import org.springframework.stereotype.Component;

@Component
public class PayEntity {

    @PreDestroy
    public void destroy(){
        System.out.println("BookEntity 銷毀前執行");
    }

    @PostConstruct
    public void afterPropertiesSet(){
        System.out.println("BookEntity執行個體化完成");
    }
}
           

弄清楚了怎麼判斷bean的初始化,我們先來看源碼

Spring5源碼分析------bean的生命周期(二)
Spring5源碼分析------bean的生命周期(二)

try中倒數第二個方法

Spring5源碼分析------bean的生命周期(二)

可以看到上面的注釋,差不多意思為初始化所有的單例

Spring5源碼分析------bean的生命周期(二)

初始化所有的單例,非懶加載

Spring5源碼分析------bean的生命周期(二)

擷取所有的beanName,并使用RootBeanDefinition注入

Spring5源碼分析------bean的生命周期(二)
Spring5源碼分析------bean的生命周期(二)

上面幾步為查詢對象是否有初始化過,沒有的話就建立到IOC容器中

Spring5源碼分析------bean的生命周期(二)

建立對象,判斷對象如果是單例的情況下調用該方法

Spring5源碼分析------bean的生命周期(二)

建立IOC對象

Spring5源碼分析------bean的生命周期(二)

通過反射執行個體化bean

Spring5源碼分析------bean的生命周期(二)

populateBean(beanName, mbd, instanceWrapper);方法是給對象set方法屬性填充

initializeBean執行初始化方法(也可以自定義初始化方法)

Spring5源碼分析------bean的生命周期(二)

判斷bean的類型是否Aware相關依賴,如果存在則回調方法

好了,重點來了

Spring5源碼分析------bean的生命周期(二)
  1. 如果 Bean 實作了 BeanNameAware 接口,則 Spring 調用 Bean 的 setBeanName() 方法傳入目前 Bean 的 id 值。
  2. 如果 Bean 實作了 BeanFactoryAware 接口,則 Spring 調用 setBeanFactory() 方法傳入目前工廠執行個體的引用。
  3. 如果 Bean 實作了 ApplicationContextAware 接口,則 Spring 調用 setApplicationContext() 方法傳入目前 ApplicationContext 執行個體的引用。

    第三點就完美解決了我們在過濾器當中,不能使用注解形式擷取bean的問題,我們可以直接通過上下文擷取bean。

好了,現在傳回到

Spring5源碼分析------bean的生命周期(二)

初始化方法之前執行處理(增強)

Spring5源碼分析------bean的生命周期(二)

2調用自定義init方法(使用java反射技術,此方法在無參構造函數後執行)

3在初始化方法之後調用(增強)

我們會發現1和3他們有一個單詞的差别,一個前一個後,也就是作用于自定義Init方法前後執行,在他們中間2也就是自定義Init方法

之後也就是調用,銷毀了。然後我們也就總結出了,bean生命周期的周期圖

Spring5源碼分析------bean的生命周期(二)

語言描述:

Bean 生命周期的整個執行過程描述如下。

1)根據配置情況調用 Bean 構造方法或工廠方法執行個體化 Bean。

2)利用依賴注入完成 Bean 中所有屬性值的配置注入。

3)如果 Bean 實作了 BeanNameAware 接口,則 Spring 調用 Bean 的 setBeanName() 方法傳入目前 Bean 的 id 值。

4)如果 Bean 實作了 BeanFactoryAware 接口,則 Spring 調用 setBeanFactory() 方法傳入目前工廠執行個體的引用。

5)如果 Bean 實作了 ApplicationContextAware 接口,則 Spring 調用 setApplicationContext() 方法傳入目前 ApplicationContext 執行個體的引用。

6)如果 BeanPostProcessor 和 Bean 關聯,則 Spring 将調用該接口的預初始化方法 postProcessBeforeInitialzation() 對 Bean 進行加工操作,此處非常重要,Spring 的 AOP 就是利用它實作的。

7)如果 Bean 實作了 InitializingBean 接口,則 Spring 将調用 afterPropertiesSet() 方法。

8)如果在配置檔案中通過 init-method 屬性指定了初始化方法,則調用該初始化方法。

9)如果 BeanPostProcessor 和 Bean 關聯,則 Spring 将調用該接口的初始化方法 postProcessAfterInitialization()。此時,Bean 已經可以被應用系統使用了。

10)如果在 中指定了該 Bean 的作用範圍為 scope=“singleton”,則将該 Bean 放入 Spring IoC 的緩存池中,将觸發 Spring 對該 Bean 的生命周期管理;如果在 中指定了該 Bean 的作用範圍為 scope=“prototype”,則将該 Bean 交給調用者,調用者管理該 Bean 的生命周期,Spring 不再管理該 Bean。

11)如果 Bean 實作了 DisposableBean 接口,則 Spring 會調用 destory() 方法将 Spring 中的 Bean 銷毀;如果在配置檔案中通過 destory-method 屬性指定了 Bean 的銷毀方法,則 Spring 将調用該方法對 Bean 進行銷毀。

直至,還有一個重要的BeanPostProcessors,其實内部的重要方法我們已經見過

Spring5源碼分析------bean的生命周期(二)

兩個處理器,當然,它遠遠沒有那麼簡單,後續揭曉