《系列二》-- 10、initialize-初始化bean

閱讀之前要注意的東西:本文就是主打流水賬式的源碼閱讀,主導的是一個參考,主要內容需要看官自己去源碼中驗證。全系列文章基於 spring 源碼 5.x 版本。

寫在開始前的話:

閱讀spring 源碼實在是一件龐大的工作,不說全部內容,單就最基本核心部分包含的東西就需要很長時間去消化了:

  • beans
  • core
  • context

實際上我在博客裏貼出來的還只是一部分內容,更多的內容,我放在了個人,fork自 spring 官方源碼倉了; 而且對源碼的學習,必須是要跟着實際代碼層層遞進的,不然只是乾巴巴的文字味同嚼蠟。

https://gitee.com/bokerr/spring-framework-5.0.x-study

這個倉設置的公共倉,可以直接拉取。



Spring源碼閱讀系列--全局目錄.md



initializeBean 方法源碼如下

    /**
	 * Initialize the given bean instance, applying factory callbacks
	 * as well as init methods and bean post processors.
	 * <p>Called from {@link #createBean} for traditionally defined beans,
	 * and from {@link #initializeBean} for existing bean instances.
	 *
	 * @param beanName the bean name in the factory (for debugging purposes)
	 * @param bean     the new bean instance we may need to initialize
	 * @param mbd      the bean definition that the bean was created with
	 *                 (can also be {@code null}, if given an existing bean instance)
	 * @return the initialized bean instance (potentially wrapped)
	 * @see BeanNameAware
	 * @see BeanClassLoaderAware
	 * @see BeanFactoryAware
	 * @see #applyBeanPostProcessorsBeforeInitialization
	 * @see #invokeInitMethods
	 * @see #applyBeanPostProcessorsAfterInitialization
	 */
	protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		} else {
			// 特殊 bean 處理   Aware BeanClassLoaderAware BeanFactoryAware
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			// init-method 執行前   後處理器
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			// 處理用戶自定義初始化方法
			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()) {
			// init-method 執行後  後處理器
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

這裏的操作其實相當簡單

"後置處理器" 是老朋友了

二、重要操作

2.1 應用 Aware

實際上它是個接口,我們可以把它叫做自動裝配。

若我們想要實現某個自動裝配操作,那麼就可以實現 Aware 接口並定義自定義的裝配行爲。

詳情可以參考下邊的博客:

《系列二》-- 11、Aware是什麼

2.2 applyBeanPostProcessorsBeforeInitialization:

執行-bean初始化前-後置處理器: 簡單的說,就是要在初始化方法(init-method) 執行前,才能進行的一些操作。
[遺憾的是,目前spring.beans 包下,除了測試包之外,spring框架中,並沒有這方面的實際應用。
也就是說你可以忽略它,這個後置處理器,目前還不會對 bean 做出任何的改動。]

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

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {// 初始化 init-method 前
			Object current = processor.postProcessBeforeInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

2.3 invokeInitMethods:

如果元數據中定義了init-method:結合包裝器 bw,以及 BeanDefinition 中記錄的元數據;
應用反射的原理,執行該 init-method.

    /**
	 * Give a bean a chance to react now all its properties are set,
	 * and a chance to know about its owning bean factory (this object).
	 * This means checking whether the bean implements InitializingBean or defines
	 * a custom init method, and invoking the necessary callback(s) if it does.
	 *
	 * @param beanName the bean name in the factory (for debugging purposes)
	 * @param bean     the new bean instance we may need to initialize
	 * @param mbd      the merged bean definition that the bean was created with
	 *                 (can also be {@code null}, if given an existing bean instance)
	 * @throws Throwable if thrown by init methods or by the invocation process
	 * @see #invokeCustomInitMethod
	 */
	protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {
		// 首先判斷是否實現了 InitializingBean 接口,如果實現了,直接調用接口方法: 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 {
				// 直接回調完成操作,適用於較高版本的 spring 
				((InitializingBean) bean).afterPropertiesSet();
			}
		}

		// 低版本中,通過在xml中配置 init-method 方式實現初始化方法
		// 此種情形下,需要通過 反射調用bean上定義的 init-method 方法.(發射存在性能損耗,不如上述的直接回調。)
		if (mbd != null && bean.getClass() != NullBean.class) {
			String initMethodName = mbd.getInitMethodName();
			if (StringUtils.hasLength(initMethodName)
					&& !(isInitializingBean && "afterPropertiesSet".equals(initMethodName))
					&& !mbd.isExternallyManagedInitMethod(initMethodName)) {
				// 利用反射執行  init-method
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}
	}

2.4 applyBeanPostProcessorsAfterInitialization

執行-bean初始化後-後置處理器: 簡單的說,就是要在初始化方法(init-method) 執行後,才能進行的一些操作。
[遺憾的是,目前spring.beans 包下,除了測試包之外,spring框架中,並沒有這方面的實際應用。
也就是說你可以忽略它,這個後置處理器,目前還不會對 bean 做出任何的改動。]

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

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			// afterInitialization: 初始化之後 - 後置處理
			Object current = processor.postProcessAfterInitialization(result, beanName);  // 初始化 init-method 之後  
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章