微信公衆號:吉姆餐廳ak 學習更多源碼知識,歡迎關注。 git
![]()
SpringBoot2 | SpringBoot啓動流程源碼分析(一)github
SpringBoot2 | SpringBoot啓動流程源碼分析(二)spring
SpringBoot2 | @SpringBootApplication註解 自動化配置流程源碼分析(三)編程
SpringBoot2 | SpringBoot Environment源碼分析(四)緩存
SpringBoot2 | SpringBoot自定義AutoConfiguration | SpringBoot自定義starter(五)springboot
SpringBoot2 | SpringBoot監聽器源碼分析 | 自定義ApplicationListener(六)bash
SpringBoot2 | 條件註解@ConditionalOnBean原理源碼深度解析(七)微信
SpringBoot2 | Spring AOP 原理源碼深度剖析(八)app
SpringBoot2 | SpingBoot FilterRegistrationBean 註冊組件 | FilterChain 責任鏈源碼分析(九)ide
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
BeanFactoryPostProcessor
和BeanPostProcessor
接口比較類似,從字面不難看出,前者多了一個 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
等註解原理基於此方法實現。 具體調用點在AbstractAutowireCapableBeanFactory
中populateBean
方法:
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: github.com/admin801122…
咱們使用 Spring 或者 SpringBoot 時,經過 Spring 預留的以上擴展接口,能夠方便的實現對 Spring IOC 過程當中的邏輯作一些擴展和加強。通 Servlet 規範同樣,能夠理解爲面向接口編程。