【spring原始碼系列】之【Bean的初始化】

小豬爸爸發表於2021-07-19

只要不放棄,希望遲早都會到來!

1. Bean的初始化

如果把bean的生命週期看作一個嬰兒誕生過程的,那麼建立例項相當於嬰兒從母體出來,一絲不掛光禿禿;屬性賦值相當於給寶寶的頭帶帽子,上身穿衣服、下神穿褲子、還有腳丫穿襪子;而初始化相當於教寶寶一些常規的動作,比如給寶寶吸奶,打嗝拍打,哄睡覺等,本篇繼續分析初始化原始碼。

2. 初始化流程概覽

3. 原始碼分析

進入initializeBean方法:

	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 {
			// 啟用aware介面
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			// 初始化前處理的beanPostProcessor , 比如aware介面,InitDestroyBeanPostProcessor,
			// ImportAwareBeanPostPorcessor 對ImportAware的支援
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			// 啟用 init-method方法
			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
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

看到流程中主要分為上述流程概覽中所述的四個步驟:
step1:啟用aware介面;
step2:初始化前處理的beanPostProcessor;
step3:啟用 init-method方法;
step4:初始化後處理的beanPostProcessor.
下面逐一分析。

啟用aware介面,原始碼如下:

	private void invokeAwareMethods(String beanName, 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);
			}
		}
	}

分別對BeanNameAware、BeanClassLoaderAware、BeanFactoryAwareaware介面進行處理,設定對應的屬性;接下來進入applyBeanPostProcessorsBeforeInitialization方法:

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

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessBeforeInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

該方法對初始化前的beanPostProcessor進行處理,對比如InitDestroyBeanPostProcessor,對@PostConstruct的支援, ApplicationContextAwareProcessor對某個Aware介面方法的呼叫,ImportAwareBeanPostPorcessor對ImportAware的支援等;

接下來InitializingBean介面和init-method 屬性呼叫對應方法為invokeInitMethods:

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

		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>) () -> {
						((InitializingBean) bean).afterPropertiesSet();
						return null;
					}, getAccessControlContext());
				}
				catch (PrivilegedActionException pae) {
					throw pae.getException();
				}
			}
			else {
				// 呼叫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)) {
				// 呼叫自定義的init方法
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}
	}

afterPropertiesSet 和 Init-method 和有@PostConstruct 註解的方法其實核心功能都是一樣的,只是呼叫時序不一樣而已,都是在該類例項化和 IOC 做完後呼叫的,我們可以在這些方法中做一些在 spring 或者 servlet 容器啟動的時候的初始化工作。比如快取預熱,比如快取資料載入到記憶體,比如配置解析,等等初始化工作呼叫順序為先呼叫@PostConstruct(註解使用)、然後是 afterPropertiesSet、InitMethod(xml 配置)方法。

最後一步,初始化後處理的beanPostProcessor,這裡最主要的是完成代理的生成,該內容放到後面AOP階段再深入。

4. 總結

本篇主要分析了bean的初始化相關操作,包括@PostConstruct註解的支援,Aware介面的支援,以及初始化後的afterPropertiesSet方法以及InitMethod方法的支援,最後完成BeanPostProcessor的後置處理,生成aop代理例項,後續將繼續分析FactoryBean介面例項化物件的過程。

相關文章