Spring Ioc源碼分析 之 Bean的加載(八):初始化

在上篇文章中,咱們詳細分析了doCreateBean()中的第5步:屬性填充,本文接着分析doCreateBean()的第6步——初始化 bean 實例對象java

本文轉自公衆號:芋道源碼編程

首先回顧下CreateBean的主流程:數組

  1. 若是是單例模式,從factoryBeanInstanceCache 緩存中獲取BeanWrapper 實例對象並刪除緩存
  2. 調用 createBeanInstance() 實例化 bean
  3. 後置處理
  4. 單例模式的循環依賴處理
  5. 屬性填充
  6. 初始化 bean 實例對象
  7. 依賴檢查
  8. 註冊bean的銷燬方法

1、初始化

Spring在對Bean進行屬性填充以後,會對Bean進行初始化,代碼以下:緩存

//AbstractAutowireCapableBeanFactory.java

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
	//JDK的安全機制驗證權限
	if (System.getSecurityManager() != null) {
		// <1> 激活 Aware 方法,對特殊的 bean 處理:Aware、BeanClassLoaderAware、BeanFactoryAware
		AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
			invokeAwareMethods(beanName, bean);
			return null;
		}, getAccessControlContext());
	}
	else {
		// <1> 激活 Aware 方法,對特殊的 bean 處理:Aware、BeanClassLoaderAware、BeanFactoryAware
		invokeAwareMethods(beanName, bean);
	}

	Object wrappedBean = bean;
	// <2> 後置處理器,before
	if (mbd == null || !mbd.isSynthetic()) {
		wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	}

	// <3> 激活用戶自定義的 init 方法
	try {
		invokeInitMethods(beanName, wrappedBean, mbd);
	}
	catch (Throwable ex) {
		throw new BeanCreationException(
				(mbd != null ? mbd.getResourceDescription() : null),
				beanName, "Invocation of init method failed", ex);
	}
	// <2> 後置處理器,after
	if (mbd == null || !mbd.isSynthetic()) {
		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	}

	return wrappedBean;
	}
複製代碼

初始化 bean 的方法其實就是三個步驟的處理,而這三個步驟主要仍是根據用戶設定的來進行初始化,這三個過程爲:安全

  • <1> 激活 Aware 方法。app

  • <2> 後置處理器。ide

  • <3> 自定義的 init 方法。post

1.一、Aware

Aware ,英文翻譯是意識到的,感知的。Spring 提供了諸多 Aware 接口,用於輔助 Spring Bean 以編程的方式調用 Spring 容器,經過實現這些接口,能夠加強 Spring Bean 的功能。學習

Spring 提供了以下系列的 Aware 接口:spa

LoadTimeWeaverAware:加載Spring Bean時織入第三方模塊,如AspectJ
BeanClassLoaderAware:加載Spring Bean的類加載器
BootstrapContextAware:資源適配器BootstrapContext,如JCA,CCI
ResourceLoaderAware:底層訪問資源的加載器
BeanFactoryAware:聲明BeanFactory
PortletConfigAware:PortletConfig
PortletContextAware:PortletContext
ServletConfigAware:ServletConfig
ServletContextAware:ServletContext
MessageSourceAware:國際化
ApplicationEventPublisherAware:應用事件
NotificationPublisherAware:JMX通知
BeanNameAware:聲明Spring Bean的名字

Aware比較複雜,後面會專門學習一下這塊內容,這裏就很少說了。

1.二、後置處理器

BeanPostProcessor 在前面介紹 bean 加載的過程曾屢次遇到,
它的做用是:
若是咱們想要在 Spring 容器完成 Bean 的實例化,配置和其餘的初始化後添加一些本身的邏輯處理,那麼請使用該接口,這個接口給與了用戶充足的權限去更改或者擴展 Spring,是咱們對 Spring 進行擴展和加強處理一個必不可少的接口。

applyBeanPostProcessorsBeforeInitialization() 方法,代碼以下:

// AbstractAutowireCapableBeanFactory.java

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
    Object result = existingBean;
    // 遍歷 BeanPostProcessor 數組
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        // 處理
        Object current = processor.postProcessBeforeInitialization(result, beanName);
        // 返回空,則返回 result
        if (current == null) {
            return result;
        }
        // 修改 result
        result = current;
    }
    return result;
}
複製代碼

applyBeanPostProcessorsAfterInitialization() 方法,代碼以下:

// AbstractAutowireCapableBeanFactory.java

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {
    Object result = existingBean;
    // 遍歷 BeanPostProcessor
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        // 處理
        Object current = processor.postProcessAfterInitialization(result, beanName);
        // 返回空,則返回 result
        if (current == null) {
            return result;
        }
        // 修改 result
        result = current;
    }
    return result;
}
複製代碼

其邏輯就是經過 getBeanPostProcessors() 方法,獲取定義的 BeanPostProcessor ,而後分別調用其 postProcessBeforeInitialization() 和 postProcessAfterInitialization() 方法,進行自定義的業務處理。

1.三、自定義init方法

在xml中有一個< bean >標籤的配置, init-method 方法,是可讓咱們在Bean初始化的時候,先執行咱們自定義的一些邏輯。
其實就是在這裏被觸發的,代碼以下:

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
    // 首先會檢查是不是 InitializingBean ,若是是的話須要調用 afterPropertiesSet()
    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
        if (logger.isTraceEnabled()) {
            logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
        }
        if (System.getSecurityManager() != null) { // 安全模式
            try {
                AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                    // <1> 屬性初始化的處理
                    ((InitializingBean) bean).afterPropertiesSet();
                    return null;
                }, getAccessControlContext());
            } catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        } else {
            // <1> 屬性初始化的處理
            ((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)) {
            // <2> 激活用戶自定義的初始化方法
            invokeCustomInitMethod(beanName, bean, mbd);
        }
    }
}
複製代碼

首先,檢查是否爲 InitializingBean 。若是是的話,須要執行 afterPropertiesSet() 方法,由於咱們除了可使用 init-method 來自定初始化方法外,還能夠實現 InitializingBean 接口。接口僅有一個 afterPropertiesSet() 方法。 二者的執行前後順序是先 <1> 的 #afterPropertiesSet() 方法,後 <2> 的 init-method 對應的方法。

相關文章
相關標籤/搜索