Spring是如何幫我維護Bean,如何進行IOC,如何解決循環依賴的呢?
Spring有兩個很重要的入口類:一個是ClassPathXMLApplicationContext,另一個是AnnotationConfigApplicationContext,這個兩個類都是擴展至AbstractApplicationContext這個類。構造上下文環境是都會調用到AbstractApplicationContext中的refresh方法,這個方法是Spring的核心方法。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
這個方法首先會創建一個BeanFactory對象,這個對象存放着所有Spring中所有的BeanDefinition對象,這個BeanDifinition對象其實就是讓Spring按照我們的要求進行實例化的約束對象,它可以告訴Spring實例化對象是應該做什麼。創建這個對象的過程其實就是解析Spring的xml文件,然後將解析結果封裝成BeanDifinition對象,讓後將這個封裝好的BeanDifinition註冊到BeanFactory裏面。具體過程我之後會寫一篇專門的博客進行解析。目前我們暫時不管,Spring實例化bean的入口是finishBeanFactoryInitialization(beanFactory)這個方法。在這個方法中會調用到beanFactory的preInstantiateSingletons()方法。這個方法裏面裏面會觸發getBean(beanName)操作,這個getBean(beanName)操作就會觸發bean的實例化。具體會調用到AbstractBeanFactory這個類裏面的doGetBean()方法。
這個方法首先會去緩存中獲取實例對象,這裏就是Spring解決循環依賴的重點了,Spring採用了三級緩存的方式來解決循環依賴問題。第一次我們進到doGetBean方法中調用getSingleton(beanName)方法時,首先會去一級緩存(singletonObjects)中獲取實例對象,獲取不到我們會接着去二級緩存中獲取實例對象(earlySingletonObjects)然後再獲取不到那我們會從三級緩存中獲取對象工廠,如果此時獲取不到對象工廠,Spring就會返回一個空對象,如果獲取到了工廠對象,我們就會從工廠對象裏獲取實例對象,並且把這個三級緩存中的beanName對應的對象工廠移除,並且把這個對象放入二級緩存中。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//根據beanName從一級緩存中拿實例
Object singletonObject = this.singletonObjects.get(beanName);
//如果獲取不到,同時判斷這個beanName是否正在實例化
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//從二級緩存中拿
singletonObject = this.earlySingletonObjects.get(beanName);
//二級緩存中沒有,判斷bean是否允許提前暴露
if (singletonObject == null && allowEarlyReference) {
//從三級緩存中拿到對象工廠
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//從工廠中拿到對象
singletonObject = singletonFactory.getObject();
//升級到二級緩存
this.earlySingletonObjects.put(beanName, singletonObject);
//刪除三級緩存
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
第一次Bean的實例肯定從緩存裏獲取不到對象,然後我們會判斷BeanDefinition的一些特性,最主要的是判斷BeanDefinition中的單例屬性,絕大部分的BeanDefinition對象是單例,所以我們會調用到
getSingleton( beanName,singletonFactory)這個方法。這個方法首先還是從緩存中獲取對象,如果獲取成功則直接返回對象,獲取失敗,則需要進行實例化了。首先它會把BeanName加入到標識着正在實例化beanName的集合中(singletonsCurrentlyInCreation),同時把新創建的單例的標誌位(newSingleton)置爲false,之後就會調用到singletonFactory中的getObject()方法,這個方法會調用到AbstractAutowireCapableBeanFactory這個類中的createBean()方法,這個方法又會調用到doCreatebean(beanName,mbd,args(這個是null))方法。
這個方法首先會從調用 createBeanInstance(beanName, mbd, args) 進行創建實例化對象(大部分採用的是無參構造器進行創建,其他實例化過程比較複雜,有興趣可以去看一下,本文以無參構造器爲例),這個方法執行完後會返回一個BeanWrapper對象,這個對象主要是對Bean和Bean的Class類的封裝,接着我們會執行到applyMergedBeanDefinitionPostProcessors()這個方法,這個方法主要做遍歷BeanPostProcessor接口的實現類,找到實現了MergedBeanDefinitionPostProcessor這個接口的BeanDifinitionPostProcessor接口,然後調用他們的postProcessMergedBeanDefinition()方法,其中最主要的兩個實現類爲AutowireAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor這兩個實現類,
AutowireAnnotationBeanPostProcessorProcessor這個類是對@Autowire註解的支持,主要是將Bean的Class對象進行解析,構造一個InjectionMetadata對象,這個對象可以理解爲是需要實例化類的元數據對象,並把類中對應的屬性構造成屬性元數據 InjectionElement對象,構造完成後類的元數據對象放入injectionMetadataCache緩存中,通過封裝爲DI做準備。
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
完成這些操作後,此時實例化對象堆中已經開闢了內存空間,但是屬性值爲空,此時Spring會將這個這個Bean加入到三級緩存中。接着就開始進行DI了,具體DI的入口方法是populateBean(beanName, mbd, instanceWrapper);這個也是對於BeanPostProcessor方法遍歷,找到實現了InstantiationAwareBeanPostProcessor這個接口的對象,並且調用postProcessProperties(pvs, bw.getWrappedInstance(), beanName)這個方法。其實主要還是剛纔兩個類(AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor)中的方法調用。其中的最主要的就是遍歷metadata對象中的InjectionElement集合,然後調用InjectionElement的injectinject(target, beanName, pvs)這個方法,CommonAnnotationBeanPostProcessor是通過這個方法調用到getResourceToInject(target, requestingBeanName)這個方法進而觸發另外一個對象的getBean操作了。
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
if (StringUtils.hasLength(this.beanName)) {
if (beanFactory != null && beanFactory.containsBean(this.beanName)) {
// Local match found for explicitly specified local bean name.
//此處觸發了另一個類的getBean操作
Object bean = beanFactory.getBean(this.beanName, this.lookupType);
if (requestingBeanName != null && beanFactory instanceof ConfigurableBeanFactory) {
((ConfigurableBeanFactory) beanFactory).registerDependentBean(this.beanName, requestingBeanName);
}
return bean;
}
else if (this.isDefaultName && !StringUtils.hasLength(this.mappedName)) {
throw new NoSuchBeanDefinitionException(this.beanName,
"Cannot resolve 'beanName' in local BeanFactory. Consider specifying a general 'name' value instead.");
}
}
// JNDI name lookup - may still go to a local BeanFactory.
return getResource(this, requestingBeanName);
}
}
而AutowiredAnnotationBeanPostProcessor是通過調用
beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter)這個方法,然後通過這個方法觸發屬性的getBean()操作的。
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
//這裏將會觸發getBean的操作
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
觸發getBean()操作就會造成新的Bean的實例化過程。當整個過程完成後,會調用到AbstractAutowireCapableBeanFactory類中的initializeBean()這個方法,這個方法主要會完成bean實例化完成後的一些特殊操作,如SpringAOP 就是在這個方法中完成的,具體如果實現的可以看我另一篇博客。完成後會將Bean封裝到DisposableBeanAdapter對象中,並把這個DisposableBeanAdapter對象添加到一個Map集合中。完成這些後會將Bean返回。返回bean後就要回到我麼的DefaultSingletonBeanRegister這個類的getSlingleton方法中,然後將新建標誌置爲true,然後將這個BeanName從正在實例的集合(singletonsCurrentlyInCreation)中移除,並且將這個Bean加入到一級緩存中(singletonObjects)。至此基本完成了Bean的實例化。
具體流程圖