Spring源碼解析之IoC容器
大家好,幾年前筆者寫過一篇關於Spring的IoC容器相關文章,出門左轉還可以找到它。工作幾年,幾乎每天都離不開Spring的框架,從最開始的SSH到現在的SSM,從以前的XML配置文件到現在的註解,Spring的使用也越來越方便,但同時也會讓我們忘了它優雅的背後是許多前輩和同行的努力。也不算立個Flag,準備有時間就寫寫Spring源碼的解析,可能會涉及架構,設計模式等,寫到哪裏算哪裏,如果寫的多了再開個專欄,優化一下。
- BeanFactory容器設計原理
- ApplicationContext容器設計原理
- BeanDefinition資源定位
- BeanDefinition加載解析
- BeanDefinition註冊
- IoC容器的依賴注入
Spring的IoC
應該說,Spring的IoC是整個框架基礎的基礎,IoC(控制反轉)解決最根本的問題是組件之間的高耦合,組件間高耦合的壞處和低耦合的好處就不囉嗦了,這裏要稍微講下,IoC和依賴注入並不是完全相等的,IoC其實是包括依賴注入(DI)和依賴查找(DL).Spring的IoC更多的是使用依賴注入(依賴注入分爲:接口注入、setter注入、構造函數注入;Spring的IoC中,setter注入是常見方式,其次是構造函數注入),因爲它更準確的描述了IoC的設計理念,將組件之間的依賴關係由Spring的IoC容器在應用系統運行期來決定,由容器動態地將某種依賴關係的目標對象實例注入到應用系統中的各個關聯的組件之中。依賴查找是容器中的受控對象通過容器的API(例如getBean())來查找自己所依賴的資源和協作對象。這種方式雖然降低了對象間的依賴,但是同時也使用到了容器的API,造成了我們無法在容器外使用和測試對象。
Spring的使用現在更多是使用註解的方式,但本文還是會用之前更常用的XML配置的方式作爲解析的入口。
BeanFactory容器設計原理
作爲容器,先必須提到bean,它是Spring中最核心的概念了,是Spring容器所承載的單位載體。一個bean在配置文件中聲明方式簡單的形如:
<bean id="testBean" class="org.bayes.model.TestBean"/>
是的,相信對Spring有一定使用經驗的你已經知道了,這樣簡單的配置就可以在Spring啓動時對TestBean.class進行實例化了。問題是,Spring是如何做到的?不妨我們大膽設想一下,完成Bean實例化的過程:
- 加載並讀取XML配置文件。
- 解析配置文件中的bean標籤及其內容。
- 實例化對應的class。
當然,這3個步驟是非常簡單,Spring的實現在步驟上差不多,後面會講到;但Spring在實現這幾個步驟的功能時是非常複雜的,先上個圖,大家簡單感受一下:
這個是Spring的IoC容器中BeanFactory接口的實現,另一個是ApplicationContext應用上下文作爲容器的高級形態存在(後面我們再講)。BeanFactory提供了最基本的IoC容器功能,以及所應遵循的最基本的服務約束。下面是BeanFactory接口定義:
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
boolean containsBean(String name);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
String[] getAliases(String name);
}
可以看到,用戶在使用容器時,可以使用轉義符“&”來得到FactoryBean本身,以區分通過容器獲取FactoryBean產生的對象和FactoryBean自身。在Spring框架下,所有Bean都是由BeanFactory(IoC容器)來管理的,但對於FactoryBean來說,它不是一般的Bean,而是一個能“創造”或“修飾”實例對象的工廠Bean。在BeanFactory接口的基礎上,我們以XmlBeanFactory的實現爲例來簡單說明IoC容器關於BeanFactory實現的設計原理。
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
DefaultListableBeanFactory和XmlBeanDefinitionReader兩個核心類已經出現了。其中DefaultListableBeanFactory是bean加載的核心,它是Spring註冊及加載Bean的默認實現。XmlBeanDefinitionReader是對XML配置文件的讀取、解析及註冊的功能實現。還記得上面“大膽設想”Bean實例化過程的3個步驟嗎,上面代碼中**this.reader.loadBeanDefinitions(resource);**便是資源加載的入口,那我們就從XmlBeanDefinitionReader.loadBeanDefinitions(resource)開始。接下來,XmlBeanDefinitionReader做了2件事來爲BeanDefinition的加載註冊做準備:
- 獲取XML文件的驗證模式(DTD / XSD)。
- 加載XML文件,並得到相應的Document。
註冊BeanDefinition是在XmlBeanDefinitionReader中實例化DefaultBeanDefinitionDocumentReader.registerBeanDefinitions方法來完成的。最終使用BeanDefinitionReaderUtils.registerBeanDefinition()方法(BeanDefinitionRegistry接口)實現註冊的是DefaultListableBeanFactory.registerBeanDefiniton()。至此,XmlBeanFactory的實現就完成了IoC容器的創建,後面就可以直接使用IoC容器了。
其實,這裏面的代碼還比較繞,經常是進到代碼塊裏面後就找不到自己的位置了。對照上面的圖片(重要步驟由紅色字體標註,核心方法名稱已在類名下寫了出來),讀者朋友可以找源碼仔細看看,相信對理解整個BeanFactory接口架構有更好的幫助。
ApplicationContext容器設計原理
相比簡單的BeanFactory基本IoC容器,我們經常使用應該是ApplicationContext應用上下文的高級形態IoC容器。下面主要以FileSystemXmlApplicationContext的實現爲例說明,附以XmlWebApplicationContext和ClassPathXmlApplicationContext。還是延續慣例,先上張圖說明一下ApplicationContext接口實現及其與BeanFactory接口的關係:
ApplicationContext的IoC容器初始化是由refresh()方法來啓動的。這個啓動包括BeanDefinition的Resource定位、載入、註冊三個過程。IoC的初始化過程不包括Bean依賴注入的實現,依賴注入一般發生在第一次getBean時(bean的lazyinit屬性可改變bean的依賴注入過程)。初始化過程完成後我們再分析一下IoC容器如何對Bean的依賴進行注入的。
首先是Resource定位,即BeanDefinition的資源定位,它由ResourceLoader統一的Resource接口完成,我們使用FileSystemXmlApplicationContext應用上下文,自然會使用FileSystemResouce來進行抽象;如果是ClassPath的Bean定義信息可以使用ClassPathResource,等等。
然後是BeanDefinition的載入,即將用戶定義好的Bean表示成IoC容器內部的數據結構BeanDefinition,這裏載入也會順帶涉及到解析的過程。
最後是使用BeanDefinitionRegistry接口實現完成向IoC容器註冊上面解析的BeanDefinition。
BeanDefinition資源定位
我們從FileSystemXmlApplicationContext具體實現開始:
package org.springframework.context.support;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {
...
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
@Override
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemResource(path);
}
}
上面提過一下,初始化是從refresh()開始的,但這裏我們暫時先重點關注getResourceByPath(path);這個getResourceByPath是在父類AbstractXmlApplicationContext中loadBeanDefinition()方法裏調用;XmlBeanDefinitionReader的loadBeanDefinition中被調用的,loadBeanDefinition採用了模板模式,具體的定位實現是由各個子類完成的。這裏的XmlBeanDefinitionReader就是在上面BeanFactory容器設計裏提到的,同時這個loadBeanDefinition()是使用DefaultListableBeanFactory作爲參數傳入。至此FileSystemXmlApplicationContext將之前講到的BeanFactory容器體系的兩大核心類都引入進來了。
BeanDefinition的加載解析
引入了DefaultListableBeanFactory和XmlBeanDefinitionReader後就沒有什麼新鮮的東西了,具體看看加載和解析的代碼吧:
package org.springframework.beans.factory.xml;
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
...... //代碼太多,省略一部分
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
......
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//***************這裏是重點*********
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
......
}
finally {
......
}
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
....
}
}
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
//***************DefaultDocumentLoader來了,資源加載的具體實現********************
return new DefaultDocumentLoader().loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
//**************調用註冊的方法,具體實現是在DefaultListableBeanFactory裏*************
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
return BeanDefinitionDocumentReader.class.cast(
BeanUtils.instantiateClass(DefaultBeanDefinitionDocumentReader.class)
);
}
}
代碼的思路還是比較清晰的,關於解析部分,是在BeanDefinitionParserDelegate類中,讀者朋友可以再追蹤者看下相關源碼。
BeanDefinition註冊
上面加載後,就可以將BeanDefinition註冊到容器中準備開始使用了。進入到DefaultBeanDefinitionDocumentReader的registerBeanDefinitions()方法裏看看,
package org.springframework.beans.factory.xml;
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate; //將元素轉換爲BeanDefinition的實現類
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("...");
}
return;
}
}
}
preProcessXml(root); //空方法,留給子類重寫
//具體實現在下一段
parseBeanDefinitions(root, this.delegate);
postProcessXml(root); //空方法,留給子類重寫
this.delegate = parent;
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (Node node : nl){
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate); //具體實現在下一段
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate); //重點快來了,接着往後看
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
/**
* 註冊的實現,這裏的getReaderContext.getRegistry()即是開始條用時傳入的
* XmlBeanDefinitionReader.getRegistry();也就是DefaultListableBeanFactory
* 它是在AbstractXmlApplicationContext裏loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
* 時傳入定義的
*/
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
}
所謂註冊的簡單實現就是將 beanName 和對應的 DeanDefinfition放到一個Map裏,當然,spring在處理時會稍微複雜一點,後面DefaultListableBeanFactory的代碼就不再展示了,有興趣的同學可以去看看。
萬里長征感覺終於快走完了,心中不免小小的激動一下,但是慢着,只是到註冊這一步是沒有用的,Spring的核心要實現的是依賴注入,那麼重點是注入纔對啊!原來,我們還沒有開始啊…
IoC容器的依賴注入
上面註冊完成後,即是在IoC容器中建立了BeanDefinition的數據映射(BeanDefinitionMap),接下來分析IoC容器是如何對Bean的依賴關係進行注入的。首先,依賴注入的過程是第一次向IoC容器獲取Bean時觸發的。 當用戶向IoC容器索要Bean時,在接口BeanFactory中有一個getBean的接口定義,往下從DefaultListableBeanFactory的基類AbstractBeanFactory來看getBean的實現
package org.springframework.beans.factory.support;
...
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
...
public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args) throws BeansException {
return doGetBean(name, requiredType, args, false);
}
@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// 先判斷緩存中是否已經有創建好的單例模式的bean.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
...
//這裏完成FactoryBean的相關處理,取得FactoryBean的生產結果。
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 順着雙親BeanFactory鏈一直向上找
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
...
}
...
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 獲取當前bean所有依賴Bean,觸發getBean遞歸調用,直到取到一個沒有任何依賴的Bean爲止.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
...
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// 調用createBean方法創建Singleton Bean的實例.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// 下面的createBean是創建prototype Bean的.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
...
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,"Scope ...",ex);
}
}
}
...
}
// 對創建的Bean進行類型檢查,這個Bean已經是包含了依賴關係的Bean.
if (requiredType != null && !requiredType.isInstance(bean)) {
...
}
return (T) bean;
}
中間省略了很多代碼,重點的業務流程和判斷,我通過註釋提示的方式在上面代碼中標註出來了,可以好好看一下,重點就在於這個createBean,它是在子類AbstractAutwireCapableBeanFactory中實現的,雖然代碼很多,但還是要貼上來看看:
package org.springframework.beans.factory.support;
...
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
...
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
...
return beanInstance;
}
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) { ///如果是Singleton先把緩存中同名Bean清除
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) { //創建Bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
...
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper); //依賴關係的處理過程,後面會再重點講
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
catch (Throwable ex) {
...
}
...
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
上面的代碼中,我們重點關注createBeanInstance和populateBean,其中createBeanInstance生成Bean所包含的Java對象,這個對象生成的方式有很多種,可以通過工廠方法,也可以通過容器的Autowire特性生成,具體是方式是由相關BeanDefinition指定的。下面先看看它的代碼,後面再重點看populateBean().
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// 確認可以實例化.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
...
if (mbd.getFactoryMethodName() != null) { //使用工廠方法對Bean進行實例化
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
...
// 使用構造函數進行實例化
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// 使用默認的構造函數對Bean進行實例化
return instantiateBean(beanName, mbd);
}
//最常用的實例化過程
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() { //CGLib生成Bean,參考SimpleInstantiationStrategy
return getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
}, getAccessControlContext());
}
else {
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
...
}
}
以上就是實例化Bean對象的過程了。在Bean對象生成以後,如何把這些Bean對象的依賴關係設置好,如何把Bean對象的屬性的依賴關係處理好,就需要依據已經解析好的BeanDefinition信息。詳細的過程我們看populateBean()方法:
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues(); //從BeanDefiniton中取得設置的 property值
...
//開始依賴注入的過程,先處理Autowire的注入;可以根據Bean的名字或類型;
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
...
applyPropertyValues(beanName, mbd, bw, pvs); //對屬性進行注入
}
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
...
if (System.getSecurityManager() != null) {
if (bw instanceof BeanWrapperImpl) { //注意! 後面依賴注入發生的地方是在這個BeanWrapperImpl中完成的
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
}
...
//BeanDefinitionValueResolver對BeanDefinition的解析是在這個valueResolve中完成的
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// 爲解析值創建一個副本,副本數據會被注入到Bean中.
List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
...
// 上面提到的,依賴注入發生的地方,在BeanWrapperImpl中完成.
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
這中間還有很多代碼及其實現沒有講,但大致的思路上已經完成了對各種Bean屬性的依賴注入過程。在Bean的創建和對象依賴注入的過程中,需要依據BeanDefinition中的信息來遞歸地完成依賴注入。從上面的過程中看,這些遞歸都是以getBean爲入口的。一個遞歸是在上下文中查找需要的Bean和創建Bean的遞歸調用;另一個遞歸是在依賴注入時,通過遞歸調用容器的getBean方法,得到當前Bean的依賴Bean,同時也觸發對依賴Bean的創建和注入。在對Bean的屬性進行依賴注入時,解析的過程也是一個遞歸地過程。根據這些依賴關係,一層層地完成對Bean的創建和注入,直到最後完成當前Bean相關的整個依賴鏈的注入。
在Bean創建和依賴注入完成後,在IoC容器中建立起來一系列依靠依賴關係聯繫起來的Bean,此時的這個Bean已經不是一個簡單的Java對象的Bean了。
回顧
在對IoC容器的分析中,(參照最上面的第一張圖)重點講了一下BeanFactory和ApplicationContext體系,BeanDefinition的資源定位、加載解析和註冊,容器的依賴注入等。通過這些實現過程的分析,我們初步瞭解了IoC容器的基本工作原理和基本特性的實現思路。但是,Spring IoC容器的內涵特性非常豐富,上面粗陋的分析無法面面俱到,有興趣的同學可以參照源碼繼續探索。