Spring IoC bean 的初始化

前言

本系列所有基於 Spring 5.2.2.BUILD-SNAPSHOT 版本。由於 Spring 整個體系太過於龐大,因此只會進行關鍵部分的源碼解析。html

本篇文章主要介紹 Spring IoC 容器中 bean 的初始化階段。java

正文

咱們在Spring IoC bean 的建立一文中分析建立 bean 實例的主要流程,此時建立出來的 bean 仍是個屬性未賦值的實例,在建立完以後會進入 populateBean() 方法,即進入屬性賦值階段。咱們簡單回顧一下,上次分析過的 doCreateBean() 方法:git

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {

    // 實例化 bean
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        // 若是bean的做用域是singleton,則須要移除未完成的FactoryBean實例的緩存
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        // 經過構造函數反射建立bean的實例,可是屬性並未賦值,見下文詳解
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    // 獲取bean的實例
    final Object bean = instanceWrapper.getWrappedInstance(); 
    // 獲取bean的類型
    Class<?> beanType = instanceWrapper.getWrappedClass(); 
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }

    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                // BeanDefinition 合併後的回調,見下文詳解
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            } 
            // 省略異常處理...
            mbd.postProcessed = true;
        }
    }

    // bean的做用域是單例 && 容許循環引用 && 當前bean正在建立中
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
    // 若是容許bean提早曝光
    if (earlySingletonExposure) {
        // 將beanName和ObjectFactory造成的key-value對放入singletonFactories緩存中
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    Object exposedObject = bean;
    try {
        // 給 bean 的屬性賦值
        populateBean(beanName, mbd, instanceWrapper);
        // 初始化 bean
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    } 
    // 省略部分代碼
}

上篇文章分析了 populateBean() 方法,此次咱們總店分析 initializeBean() 方法。github

bean 的初始化

AbstractAutoCapableBeanFactory#initializeBean

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {

    // BeanAware的接口回調,見下文詳解
    invokeAwareMethods(beanName, bean);

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        // BeanPostProcessor的postProcessBeforeInitialization()回調,也就是bean初始化前的回調
        // 在 ApplicationContextAwareProcessor實現的postProcessBeforeInitialization方法中會執行
        // ApplicationContext Aware的接口回調。
        // InitDestoryAnnotationBeanPostProcessor的postProcessBeforeInitialization()中會執行
        // 標註了@PostConstruct註解的方法。
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        // 調用bean的自定義初始化方法,如afterPropertiesSet,XML中的init屬性指定的方法等
        invokeInitMethods(beanName, wrappedBean, mbd);
    } catch (Throwable ex) {
        throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
        // BeanPostProcessor的postProcessAfterInitialization()回調,也就是bean初始化後的回調
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

Aware 接口回調

AbstractAutowireCapableBeanFactory#invokeAwareMethods

private void invokeAwareMethods(final String beanName, final Object bean) {
    if (bean instanceof Aware) {
        // BeanNameAware接口方法回調
        if (bean instanceof BeanNameAware) {
            ((BeanNameAware) bean).setBeanName(beanName);
        }
        // BeanClassLoaderAware接口方法回調
        if (bean instanceof BeanClassLoaderAware) {
            ClassLoader bcl = getBeanClassLoader();
            if (bcl != null) {
                ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
            }
        }
        // BeanFactoryAware接口方法回調
        if (bean instanceof BeanFactoryAware) {
            ((BeanFactoryAware)bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
        }
    }
}

經過實現這些 Aware 接口的 bean 的被初始化以前,能夠取得一些相對應的資源,好比 beanNamebeanFactory 等。spring

bean 的初始化前回調

AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization

public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {

    Object result = existingBean;
    // 遍歷全部註冊的BeanPostProcessor實現類,調用postProcessBeforeInitialization方法
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        // 在bean初始化方法執行前,調用postProcessBeforeInitialization方法
        Object current = processor.postProcessBeforeInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

上面方法主要是調用了 BeanPostProcessorpostProcessBeforeInitialization() 方法,下面咱們看一下 BeanPostProcessor 接口的定義:緩存

public interface BeanPostProcessor {

    /**
     * bean初始化前調用,此時bean已經實例化而且屬性已經賦值,Aware接口已經回調;返回非 {@code null} 會使用返回的bean
     */
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    /**
     * bean初始化後調用,返回非 {@code null} 會使用返回的bean
     */
    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

}

調用初始化方法

AbstractAutowireCapableBeanFactory#invokeInitMethods

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {

    // bean是否實現InitializingBean接口
    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
        // 調用afterPropertiesSet方法
        ((InitializingBean) bean).afterPropertiesSet();
    }

    // 調用自定義的init方法,例如XML中init-method屬性設置的方法
    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);
        }
    }
}

咱們知道設置 bean 的初始化方法其實有三種方式 @PostConstructInitializingBean、自定義初始化方法,一個 bean 同時實現這三種方式時,調用順序以下:app

  1. @PostConstruct
  2. InitializingBean#afterPropertiesSet()
  3. 自定義初始化方法

從上面方法能夠很容易的看出 InitializingBean 接口的 afterPropertiesSet() 方法先於自定義初始化方法調用,那麼 @PostConstruct 註解標註的方法在什麼時候調用的呢?玄機就在上面介紹的 BeanPostProcessor 接口,InitDestroyAnnotationBeanPostProcessor 實現了該接口並重寫了 postProcessBeforeInitialization() 方法調用了標註 @PostConstruct 註解的方法。我會在後續文章分析其實現。函數

bean 初始化後回調

AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {

    Object result = existingBean;
    // 遍歷全部註冊的BeanPostProcessor實現類,調用postProcessAfterInitialization方法
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        // 在bean初始化方法執行後,調用postProcessBeforeInitialization方法
        Object current = processor.postProcessAfterInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

總結

本篇文章主要分析了 Spring IoC bean 的初始化階段流程,Spring 在此階段也提供了2個擴展點;分別是 bean 的初始化前和初始化後,也就是 BeanPostProcessor 接口,該接口十分重要其它 processor 接口都是直接或間接在此接口上擴展出來的。post

最後,我模仿 Spring 寫了一個精簡版,代碼會持續更新。地址:https://github.com/leisurexi/tiny-springthis

相關文章
相關標籤/搜索