SpringBoot2 | Spring IOC 流程中核心擴展接口的12個擴展點源碼分析(十一)

微信公衆號:吉姆餐廳ak
學習更多源碼知識,歡迎關注。
在這裏插入圖片描述


SpringBoot2 | SpringBoot啓動流程源碼分析(一)

SpringBoot2 | SpringBoot啓動流程源碼分析(二)

SpringBoot2 | @SpringBootApplication註解 自動化配置流程源碼分析(三)

SpringBoot2 | SpringBoot Environment源碼分析(四)

SpringBoot2 | SpringBoot自定義AutoConfiguration | SpringBoot自定義starter(五)

SpringBoot2 | SpringBoot監聽器源碼分析 | 自定義ApplicationListener(六)

SpringBoot2 | 條件註解@ConditionalOnBean原理源碼深度解析(七)

SpringBoot2 | Spring AOP 原理源碼深度剖析(八)

SpringBoot2 | SpingBoot FilterRegistrationBean 註冊組件 | FilterChain 責任鏈源碼分析(九)

SpringBoot2 | BeanDefinition 註冊核心類 ImportBeanDefinitionRegistrar (十)

SpringBoot2 | Spring 核心擴展接口 | 核心擴展方法總結(十一)


概述

Spring 的核心思想即是容器。整個容器 refresh 時,外部看似風平浪靜,內部實則一片汪洋大海。另外整個流程嚴格遵守開閉原則,內部對修改關閉,對擴展開放。

可以這麼理解:
把 Spring 容器理解爲一個鑰匙環,上面掛滿了鑰匙,每個鑰匙理解爲一個擴展接口。鑰匙的順序是固定的,可理解爲接口的調用順序固定,對修改關閉。每個鑰匙可以用來做不同的事情,可理解爲擴展接口的不同實現,對擴展開放。

Spring 提供了各種豐富的擴展接口,本篇主要對 IOC 過程中涉及的擴展接口做個整理。

對應的 UML 如下:

在這裏插入圖片描述

調用順序如下:

分別來看。


1。BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry

BeanDefinitionRegistryPostProcessor接口在讀取項目中的beanDefinition之後執行,提供的一個補充擴展接口,
用來動態註冊beanDefinition。調用點:
PostProcessorRegistrationDelegate中:

if (beanFactory instanceof BeanDefinitionRegistry) {
			//......
			// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
			boolean reiterate = true;
			while (reiterate) {
				reiterate = false;
				//獲取所有的 BeanDefinitionRegistryPostProcessor 類型的bean
				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
				for (String ppName : postProcessorNames) {
					if (!processedBeans.contains(ppName)) {
						//通過 getBean 方法進行實例化
						currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
						processedBeans.add(ppName);
						reiterate = true;
					}
				}
				sortPostProcessors(currentRegistryProcessors, beanFactory);
				registryProcessors.addAll(currentRegistryProcessors);
				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
				currentRegistryProcessors.clear();
			}
		//......
		}

示例:手動註冊BeanDefinition::

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("postProcessBeanDefinitionRegistry ...");
        //手動註冊 beanDefinition
        registry.registerBeanDefinition("myBeanDefinitionRegistrar",new AnnotatedGenericBeanDefinition(MyBeanDefinitionRegistrar.class));
    }
}

2 。BeanFactoryPostProcessor.postProcessBeanFactory

BeanFactoryPostProcessorBeanPostProcessor 接口比較相似,從字面不難看出,前者多了一個 factory,所以該接口正是beanFactory的擴展接口,使用場景:一般用來在讀取所有的beanDefinition信息之後,實例化之前,通過該接口可進一步自行處理,比如修改beanDefinition等。調用點在上面第一個擴展接口之後,也在PostProcessorRegistrationDelegate中:

if (beanFactory instanceof BeanDefinitionRegistry) {
		//......
		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// 獲取所有的 BeanFactoryPostProcessor 類型
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

		// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) {
			if (processedBeans.contains(ppName)) {
				// skip - already processed in first phase above
			}
			else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		//執行所有的 BeanFactoryPostProcessor 實現邏輯
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

		//......
		}

示例:動態修改BeanDefinition

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition myBeanDefinitionRegistrar = beanFactory.getBeanDefinition("myBeanDefinitionRegistrar");
        //可以修改 beanDefinition 信息。這裏將bean 設置爲單例
        myBeanDefinitionRegistrar.setScope(BeanDefinition.SCOPE_SINGLETON);
    }
}

3。InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation

Instantiation 實例化的意思,和Initialization初始化 比較相似,容易混淆。
postProcessBeforeInstantiation用來獲取 bean,如果獲取到,則不再執行對應 bean的初始化之前流程,直接執行後面要講的postProcessAfterInitialization方法。
調用點在AbstractAutowireCapableBeanFactory中:

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

		//......
		try {
			//執行實例化之前的方法
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}
		//......
	}
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			// Make sure bean class is actually resolved at this point.
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
					//開始執行 postProcessBeforeInstantiation 方法
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					//如果獲得結果不爲空,則直接執行實例化之後的擴展接口。結束 bean 實例化流程。
					if (bean != null) {
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}

如果postProcessBeforeInstantiation獲得結果不爲空,則結束 bean 實例化流程。


4。SmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors

該擴展點決定判斷合適的 bean 構造方法。
具體可參考AutowiredAnnotationBeanPostProcessor實現類,針對以下使用場景:
MyComponent1中通過構造方法注入MyComponent2:

@Autowired
    public MyComponent(MyComponent2 component2){
        System.out.println("myComponent init...");
    }

這裏會判斷選擇出合適的構造方法,並實例化需要的參數 bean。
調用點在AbstractAutowireCapableBeanFactory中:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		//......
		//獲取合適的構造方法,如果爲空,則走默認的構造方法。
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null ||
				mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
		   //如果發現有構造方法引用了依賴注入註解,比如:@AutoWired,則調用autowireConstructor方法進行注入
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// No special handling: simply use no-arg constructor.
		return instantiateBean(beanName, mbd);
	}

5。MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition

該接口用來合併BeanDefinition,也是對BeanDefinition處理一種擴展接口。
最常用的使用場景:AutowiredAnnotationBeanPostProcessor實現類中,通過該接口解析當前 bean 中所有
指定註解類型的屬性:

  	    this.autowiredAnnotationTypes.add(Autowired.class);
	    this.autowiredAnnotationTypes.add(Value.class);

默認解析上兩種註解的屬性,將其描述信息合併到當前對象的beanDefinition中,在後面屬性填充populateBean的過程中,會取出這些對象,進行注入。
調用點在AbstractAutowireCapableBeanFactory中:

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

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		//實例化 bean
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
				    //執行 postProcessMergedBeanDefinition 邏輯
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}
		//......
		return exposedObject;
	}

6。InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation

實例化之後調用的方法,在AbstractAutowireCapableBeanFactory.populateBean()填充方法中會觸發。
該方法默認返回爲true,如果返回false,則中斷populateBean方法,即不再執行屬性注入的過程。
實際項目中,該擴展方法使用不多。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		// ......
		boolean continueWithPropertyPopulation = true;

		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
						continueWithPropertyPopulation = false;
						break;
					}
				}
			}
		}

		if (!continueWithPropertyPopulation) {
			return;
		}
		//......
	}

7。SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference

getEarlyBeanReference方法只要有在 Spring 發生循環依賴時調用。首先,當bean 創建時,爲了防止後續有循環依賴,會提前暴露回調方法,用於 bean 實例化的後置處理。getEarlyBeanReference方法就是在提前暴露的回調方法中觸發。

具體調用點在DefaultSingletonBeanRegistry

@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		//如果 bean 還未實例化,並且正在創建中。
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
			//判斷是否已經提前提前暴露了bean 引用。
				singletonObject = this.earlySingletonObjects.get(beanName);
				//如果運行循環依賴
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
					//則調用 getObject() 方法
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

getObject()中調用getEarlyBeanReference方法完成 bean的初始化流程。

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
				}
			}
		}
		return exposedObject;
	}

大致的流程:

當A實例化之後,Spring IOC會對A依賴的屬性進行填充,此時如果發現A依賴了B,會去實例化B。同樣在填充B的屬性時,如果B也引用了A,就發生了循環依賴。因爲A還未創建完成,還未注入Spring中。

Spring的做法是通過對創建中的緩存一個回調函數,類似於一個埋點操作,如果後續填充屬性階段,發生了循環依賴,則通過觸發該回調函數來結束該bean的初始化。

​當對A實例化時,會提前暴露一個回調方法 ObjectFactory(Spring5中改爲了函數式接口) 放入緩存。當B引用A,發現A還未實例化結束,就會通過緩存中的回調方法結束A的初始化流程,然後注入B。然後繼續A的填充屬性流程,將B注入A,然後結束循環依賴。

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		//......
		if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			//添加回調方法,循環依賴時會回調
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}
		try {
		//填充屬性,也就是發生循環依賴的地方
			populateBean(beanName, mbd, instanceWrapper);
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}
		//......

8。InstantiationAwareBeanPostProcessor.postProcessPropertyValues

該方法用於屬性注入,在 bean 初始化階段屬性填充時觸發。@Autowired,@Resource 等註解原理基於此方法實現。
具體調用點在AbstractAutowireCapableBeanFactorypopulateBean方法:

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		//......
	if (hasInstAwareBpps || needsDepCheck) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			if (hasInstAwareBpps) {
				for (BeanPostProcessor bp : getBeanPostProcessors()) {
					if (bp instanceof InstantiationAwareBeanPostProcessor) {
						InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
						//獲取該方法的所有實現類
						pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvs == null) {
							return;
						}
					}
				}
			}
			if (needsDepCheck) {
				checkDependencies(beanName, mbd, filteredPds, pvs);
			}
		}

		//......
	}

上述方法會獲取所有postProcessPropertyValues的實現方法。例如:在AutowiredAnnotationBeanPostProcessor中實現方式如下,也就是依賴注入的實現代碼:

@Override
	public PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {

		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
			metadata.inject(bean, beanName, pvs);
		}
		catch (BeanCreationException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
		}
		return pvs;
	}

9。ApplicationContextAwareProcessor.invokeAwareInterfaces

該擴展點用於執行各種驅動接口。在 bean實例化之後,屬性填充之後,通過擴展接口,執行如下驅動接口:

private void invokeAwareInterfaces(Object bean) {
		if (bean instanceof Aware) {
			if (bean instanceof EnvironmentAware) {
				((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
			}
			if (bean instanceof EmbeddedValueResolverAware) {
				((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
			}
			if (bean instanceof ResourceLoaderAware) {
				((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
			}
			if (bean instanceof ApplicationEventPublisherAware) {
				((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
			}
			if (bean instanceof MessageSourceAware) {
				((MessageSourceAware) bean).setMessageSource(this.applicationContext);
			}
			if (bean instanceof ApplicationContextAware) {
				((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
			}
		}
	}

所以,只需要實現以上6種驅動接口,就可以獲得對應的容器相關的變量。這些變量在實際項目中是比較常用的了。

使用方式:

@Component
public class MyComponent implements ApplicationContextAware, InitializingBean, BeanClassLoaderAware ,ResourceLoaderAware,EnvironmentAware {

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet init...");
    }
    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("setBeanClassLoader init...");
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        System.out.println("setApplicationContext init...");
    }
    @Override
    public void setEnvironment(Environment environment) {

        System.out.println("setEnvironment init...");
    }
    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        System.out.println("setResourceLoader init...");
    }
}

10。BeanFactoryPostProcessor.postProcessBeforeInitialization

BeanFactoryPostProcessor中的兩個擴展接口是 Spring IOC過程中最後兩個擴展接口。其中postProcessBeforeInitialization用於在 bean 實例化之後,afterPropertiesSet方法之前執行的前置接口。
用於對 bean 進行一些屬性設置,上面的設置驅動的方法invokeAwareInterfaces便是實現了此接口。
調用點如下:

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 {
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
		//執行前置擴展方法
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}
		try {
		//執行 afterPropertiesSet 方法
			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()) {
		//執行後置擴展方法
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

11。InitializingBean.afterPropertiesSet

用於bean實例化之後,設置屬性的方法。
上面已經提到,在invokeInitMethods方法中會觸發該方法調用:

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {
		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 {
				//執行afterPropertiesSet
					AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
						((InitializingBean) bean).afterPropertiesSet();
						return null;
					}, getAccessControlContext());
				}
				catch (PrivilegedActionException pae) {
					throw pae.getException();
				}
			}
			else {
			//執行afterPropertiesSet
				((InitializingBean) bean).afterPropertiesSet();
			}
		}
	}

12。BeanFactoryPostProcessor.postProcessAfterInitialization

該方法Spring IOC過程中最後一個常用的擴展點,用於 bean 初始化之後的後置處理。IOC 流程執行到此處,一個完整的 bean 已經創建結束,可在此處對 bean 進行包裝或者代理。Spring AOP 原理便是基於此擴展點實現,實現方式在AbstractAutoProxyCreator中:

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (!this.earlyProxyReferences.contains(cacheKey)) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

有興趣的可以移步 Spring AOP相關的文章:SpringBoot2 | Spring AOP 原理源碼深度剖析(八)

具體使用方式已上傳至 github:
https://github.com/admin801122/springboot2-spring5-studying/tree/master/ioc-beanPostProcessor

在這裏插入圖片描述


總結

我們使用 Spring 或者 SpringBoot 時,通過 Spring 預留的以上擴展接口,可以方便的實現對 Spring IOC 過程中的邏輯做一些擴展和增強。通 Servlet 規範一樣,可以理解爲面向接口編程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章