spring源碼:bean加載之創建bean-初始化bean

一、介紹

  初始化bean的動作是在創建bean給bean填充屬性之後,目的是爲了調用用戶自定義的初始化方法。期間還涉及到Aware接口和BeanPostProcessor的處理,處理流程如下:
在這裏插入圖片描述

二、bean加載流程

  1. 獲取用戶傳入name對應的beanName
  2. 嘗試從緩存中獲取bean實例
  3. 緩存中不存在,加載bean實例
    3.1. 檢查循環依賴
    3.2 處理parentBeanFactory
    3.3 處理依賴的bean(dependsOn)
    3.4 三種bean實例的創建
     3.4.1 單例bean的創建
      3.4.1.1 獲取單例bean,getSingleton()方法
      3.4.1.2 準備創建bean,createBean()方法
      3.4.1.3 創建bean,doCreateBean()方法
       3.4.1.3.1 創建BeanWrapper
       3.4.1.3.2 記錄bean的Object-Factory
       3.4.1.3.3 屬性填充
       3.4.1.3.3 初始化bean(本章解析
     3.4.2 原型bean的創建
     3.4.3 根據scope策略創建bean
  4. 從bean實例中獲取真正的對象
  5. 轉換對象類型
  6. 返回對象實例

三、主要方法

  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean:初始化bean的整體流程
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods:調用具體Aware接口的對應方法
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeInitMethods:調用用戶自定義的初始化方法

四、源碼分析

1. 初始化bean流程

	protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			// 1. 調用Aware類型bean的對應方法
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			// 2. 初始化前,應用後處理器
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			// 3. 激活用戶自定義的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()) {
			// 4. 初始化後,應用後處理器
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

從代碼中可以看到,初始化bean不僅僅是調用用戶自定義的初始化方法。而是經歷了以下四個步驟:

  1. 如果bean是Aware類型,則調用具體Aware的對應方法
  2. 調用BeanPostProcessor的postProcessBeforeInitialization方法
  3. 調用bean的初始化方法
  4. 調用BeanPostProcessor的postProcessAfterInitialization方法

2. 給Aware類型的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);
			}
		}
	}

如果該bean實現了某種Aware接口,初始化的時候spring就會調用該接口的特定方法,來給bean傳遞某種類型的值。目前一共有三種Aware接口:BeanNameAware(獲取bean名稱)、BeanClassLoaderAware(獲取類加載器)、BeanFactoryAware(獲取bean工廠)。

3. 調用bean的初始化方法

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

		// 1. 如果是InitializingBean類型的bean,調用bean的afterPropertiesSet方法
		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 {
				// 調用bean的afterPropertiesSet方法
				((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);
			}
		}
	}

如果bean實現了InitializingBean接口,則先調用afterPropertiesSet方法;然後調用用戶自定義的初始化方法。指定初始化方法的方式如下

    <bean id="personInit" class="com.kaka.spring.pojo.Person" init-method="testInitMethod" />
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章