天天看點

分析Spring中Bean的生命周期

寫在最前

從十一到現在兩周,IOC部分源碼讀了一半多,是力氣活,也是個精細活。全部寫出來心有餘力不足,是以找些重點寫寫。

簡述 bean 執行個體化之前

Spring中不是啟動容器時就開啟bean的執行個體化程序,它首先會對資源進行讀取并對bean進行初始化。

Spring将資源的定義和資源的加載區分開,

Resource

定義了統一的資源,預設實作是

AbstractResource

,資源的加載由

ResourceLoader

接口的不同實作類傳回Resource。緊接着,解析

Resource

資源,将使用者定義的Bean裝載成

BeanDefinition

,每一個Bean對象都對應着一個

BeanDefinition

BeanDefinition

存在于IOC内部容器中的HashMap結構。再緊跟着,向IOC容器注冊解析好的

BeanDefinition

,這個過程是通過BeanDefinitionRegistry接口來實作的。

初始化之後,會進行真正bean的加載,因為

BeanDefinition

不是想要的bean。初始化預設為懶加載,第一次調用

getBean()

時進行初始化。

首先得到可使用正确的beanName,這是涉及到别名或者factoryBean 。bean的作用域有singleton,prototype 和其他,Spring先嘗試從緩存中加載單例bean,否則開始建立bean的執行個體。建立bean的執行個體可以了解為将

BeanDefinition

轉換為

BeanWrapper

,BeanWarpper提供了get、set方法。之後還有一系列處理:MergedBeanDefinitionPostProcessor 屬性合并,單例模式的循環依賴處理,屬性填充,初始化bean。

在初始化bean這個過程中的代碼,就包含了對XXXAware接口的處理,後置處理器,以及自定義的init-method方法。

Bean生命周期

回到最開始,看一下spring bean 的生命周期:

分析Spring中Bean的生命周期
  1. 執行個體化Bean

    對于BeanFactory容器,當客戶向容器請求一個尚未初始化的bean時,或初始化bean的時候需要注入另一個尚未初始化的依賴時,容器就會調用createBean進行執行個體化。

    對于ApplicationContext容器,當容器啟動結束後,便執行個體化所有的bean。

    容器通過擷取BeanDefination對象中的資訊進行執行個體化。并且這一步僅僅是簡單的執行個體化,并未進行依賴注入。

    執行個體化對象被包裝在BeanWrapper對象中,BeanWrapper提供了設定對象屬性的接口,進而避免了使用反射機制設定屬性。

    在執行個體化bean的過程中,Spring采用政策模式決定采用反射還是 CGLIB 動态位元組碼。Spring 預設采用 CglibSubclassingInstantiationStrategy執行個體化bean,他既可以以反射執行個體化對象,還可以通過 CGLIB 的動态位元組碼的方式,以方法(setXxx)的方式注入對象執行個體化。

  2. 設定對象屬性(依賴注入)

    執行個體化後的對象被封裝在BeanWrapper對象中,并且此時對象仍然是一個原生的狀态,并沒有進行依賴注入。

    緊接着,Spring根據BeanDefinition中的資訊進行依賴注入。

    并且通過BeanWrapper提供的設定屬性的接口完成依賴注入。

  3. 注入Aware接口

    緊接着,Spring會檢測該對象是否實作了xxxAware接口,并将相關的xxxAware執行個體注入給bean。

    private void invokeAwareMethods(final String beanName, final Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware) bean).setBeanName(beanName);
            }
            if (bean instanceof BeanClassLoaderAware) {
                ClassLoader bcl = getBeanClassLoader();
                if (bcl != null) {
                    ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
                }
            }
            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
            }
        }
    }
               
  4. BeanPostProcessor

    當經過上述幾個步驟後,bean對象已經被正确構造,但如果你想要對象被使用前再進行一次自定義的處理,就可以通過BeanPostProcessor接口實作。

    該接口提供了兩個函數:

    • postProcessBeforInitialzation(Object bean, String beanName)

      目前正在初始化的bean對象會被傳遞進來,我們就可以對這個bean做任何處理。

      這個函數會先于InitialzationBean執行,是以稱為前置處理。

      所有Aware接口的注入就是在這一步完成的。

    • postProcessAfterInitialzation(Object bean, String beanName)

      目前正在初始化的bean對象會被傳遞進來,我們就可以對這個bean做任何處理。

      這個函數會在initialzationBean完成後執行,是以成為後置處理

      public interface BeanPostProcessor {
          @Nullable
          default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
              return bean;
          }
      
          @Nullable
          default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
              return bean;
          }
      }
                 
  5. InitializingBean 與 init-method

    當BeanPostProcessor的前置處理完成後就會進入本階段。

    InitialzingBean接口隻有一個函數:

    • afterPropertiesSet()

    這一階段也可以在bean正式構造完成前增加我們自定義的邏輯,但它與前置處理不同,由于該函數并不會把目前bean傳遞進來,是以這一步沒辦法處理對象本身,隻能增加一些額外的邏輯。若要使用它,我們需要讓bean實作該接口,并把要增加的邏輯寫在該函數中。然後Spring會在前置處理完成後檢測目前bean是否實作了該接口,并執行afterPropertiesSet函數。

    當然,Spring為了降低對客戶代碼的侵入性,給bean的配置提供了init-method屬性,該屬性指定了在這一階段需要執行的函數名。Spring便會在初始化階段執行我們設定的函數。init-method本質上仍然使用了InitializingBean的接口。

    protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
        throws Throwable {
    
        boolean isInitializingBean = (bean instanceof InitializingBean);
        if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
            if (logger.isDebugEnabled()) {
                logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
            }
            if (System.getSecurityManager() != null) {
                try {
                    AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                        ((InitializingBean) bean).afterPropertiesSet();
                        return null;
                    }, getAccessControlContext());
                }
                catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            }
            else {
                ((InitializingBean) bean).afterPropertiesSet();
            }
        }
    
        if (mbd != null && bean.getClass() != NullBean.class) {
            String initMethodName = mbd.getInitMethodName();
            if (StringUtils.hasLength(initMethodName) &&
                !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                !mbd.isExternallyManagedInitMethod(initMethodName)) {
                invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
    }
               
  6. DisposableBean 和 destroy-method

    和init-method一樣,通過給destroy-method指定函數,就可以在bean銷毀前執行指定的邏輯。

執行個體代碼

先來一段代碼,看看Spring中Bean的生命周期

public class LifeCycleBean implements BeanNameAware, BeanFactoryAware, BeanClassLoaderAware, InitializingBean,DisposableBean  {
    private String test;

    public LifeCycleBean() {
        System.out.println("構造函數調用...");
    }

    public String getTest() {
        return test;
    }

    public void display(){
        System.out.println("方法調用...");
    }

    public void setTest(String test) {
        System.out.println("屬性注入....");
        this.test = test;
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("BeanNameAware 被調用...");
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("BeanClassLoaderAware 被調用...");
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("BeanFactoryAware 被調用...");
    }

    public void initMethod(){
        System.out.println("init-method 被調用...");
    }

    public void destroyMethod(){
        System.out.println("destroy-method 被調用...");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean afterPropertiesSet 被調動...");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean destroy 被調動...");
    }
}
           
<bean id="lifeCycleBean" class="com.example.bean.LifeCycleBean"
      init-method="initMethod" destroy-method="destroyMethod">
    <property name="test" value="test"/>
</bean>
           
public static void main(String[] args) {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/applicationContext.xml");

    LifeCycleBean lifeCycleBean = (LifeCycleBean) context.getBean("lifeCycleBean");
    lifeCycleBean.display();

    context.destroy();
}
           

運作結果如下:

構造函數調用...
屬性注入....
BeanNameAware 被調用...
BeanClassLoaderAware 被調用...
BeanFactoryAware 被調用...
InitializingBean afterPropertiesSet 被調動...
init-method 被調用...
方法調用...
DisposableBean destroy 被調動...
destroy-method 被調用...