深入Spring源碼解析---Spring-Bean的創建,以及Spring如何解決循環依賴問題

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的實例化。

具體流程圖
在這裏插入圖片描述

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