1. 場(chǎng)景
一個(gè)applicationContext.xml配置文件,這個(gè)不可少一個(gè)bean,這里我沒用接口,直接用一個(gè)普通的類做為Spring的bean
一個(gè)Junit測(cè)試類
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="studentBean" class="my.StudentBean"></bean>
</beans>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="studentBean" class="my.StudentBean"></bean>
</beans>
StudentBean
public class StudentBean{
public void getName(String name) {
System.out.println("你的名字是:" + name);
}
}
public void getName(String name) {
System.out.println("你的名字是:" + name);
}
}
單元測(cè)試類
1 public class MyTest {
2
3 public static void main(String[] args) {
4 ClassPathResource res = new ClassPathResource("my/applicationContext.xml");
5
6 XmlBeanFactory bf = new XmlBeanFactory(res);
7
8 StudentBean bean = (StudentBean)bf.getBean("studentBean");
9
10 bean.getName("yangay");
11 }
12 }
運(yùn)行單元測(cè)試,打印出“你的名字是:yangay”,測(cè)試類只有四行代碼,但Spring到底為我們做了些什么?下面我們就基于這樣的場(chǎng)景去分析bean的加載過(guò)程。2
3 public static void main(String[] args) {
4 ClassPathResource res = new ClassPathResource("my/applicationContext.xml");
5
6 XmlBeanFactory bf = new XmlBeanFactory(res);
7
8 StudentBean bean = (StudentBean)bf.getBean("studentBean");
9
10 bean.getName("yangay");
11 }
12 }
2. 初步分析
(1) 獲取配置文件
在Spring內(nèi)部,有超過(guò)十個(gè)以Resource結(jié)尾的類或文件,他們處理不同類型的資源文件,如FileSystemResource、ClassPathResource、UrlResource等,處理過(guò)程大同小異,內(nèi)部細(xì)節(jié)可以不必關(guān)心,跟其他組件邏輯幾乎沒關(guān)系。
要跟蹤這個(gè)處理過(guò)程,大致流程如下:
a. 構(gòu)造XmlBeanFactory時(shí),會(huì)調(diào)用Reader對(duì)象的loadBeanDefinitions方法去加載bean定義信息
b. 在Reader對(duì)象的doLoadBeanDefinitions驗(yàn)證文檔(配置文件)模式,然后通過(guò)documentLoader對(duì)象處理資源對(duì)象,生成我們Document對(duì)象;
c. 調(diào)用BeanDefinitionDocumentReader對(duì)象的doRegisterBeanDefinitions去注冊(cè)bean定義信息;
d. parseBeanDefinitions從xml文檔根節(jié)點(diǎn)遞歸循環(huán)處理各個(gè)節(jié)點(diǎn),對(duì)bean節(jié)點(diǎn)真正的處理工作委托給了BeanDefinitionParserDelegate,方法parseBeanDefinitionElement將一個(gè)bean節(jié)點(diǎn)轉(zhuǎn)換成一個(gè)BeanDefinitionHolder對(duì)象,這才是最終的解析過(guò)程;
e. DefaultListableBeanFactory.registerBeanDefinition利用解析好的beanDefinition對(duì)象完成最終的注冊(cè),其實(shí)就是把beanName和beanDefinition作為鍵值對(duì)放到beanFactory對(duì)象的map;
(3) 實(shí)例化Bean
(4) 調(diào)用對(duì)象的方法,沒什么好說(shuō)的。當(dāng)然如果方法上做了事務(wù)、AOP之類的聲明,這一步的處理就不會(huì)那么簡(jiǎn)單了。
對(duì)于配置文件,解析也解析完了,裝飾也裝飾完了,已經(jīng)把xml中bean元素的各屬性封裝到了BeanDefinition對(duì)象,已經(jīng)可以滿足后續(xù)的使用要求了,剩下的工作便是注冊(cè)解析的BeanDefinition。3.7 BeanDefinitionReaderUtils.registerBeanDefinition
ClassPathResource res = new ClassPathResource("my/applicationContext.xml");
這一句只是讀入配置文件,并封裝成Spring提供的Resource對(duì)象,供后面邏輯使用。在Spring內(nèi)部,有超過(guò)十個(gè)以Resource結(jié)尾的類或文件,他們處理不同類型的資源文件,如FileSystemResource、ClassPathResource、UrlResource等,處理過(guò)程大同小異,內(nèi)部細(xì)節(jié)可以不必關(guān)心,跟其他組件邏輯幾乎沒關(guān)系。
(2) 解析配置文件并注冊(cè)bean
XmlBeanFactory bf = new XmlBeanFactory(res);
這里面的邏輯相當(dāng)復(fù)雜,涉及到眾多Factory、Reader、Loader、BeanDefinition、Perser、Registry系列接口和類,但他們做的基本事情就是將applicationContext.xml配置的Bean信息構(gòu)成BeanDefinition對(duì)象,然后放到Factory的map中(這一步就是所謂的注冊(cè)),這樣以后程序就可以直接從Factory中拿Bean信息了。要跟蹤這個(gè)處理過(guò)程,大致流程如下:
a. 構(gòu)造XmlBeanFactory時(shí),會(huì)調(diào)用Reader對(duì)象的loadBeanDefinitions方法去加載bean定義信息
b. 在Reader對(duì)象的doLoadBeanDefinitions驗(yàn)證文檔(配置文件)模式,然后通過(guò)documentLoader對(duì)象處理資源對(duì)象,生成我們Document對(duì)象;
c. 調(diào)用BeanDefinitionDocumentReader對(duì)象的doRegisterBeanDefinitions去注冊(cè)bean定義信息;
d. parseBeanDefinitions從xml文檔根節(jié)點(diǎn)遞歸循環(huán)處理各個(gè)節(jié)點(diǎn),對(duì)bean節(jié)點(diǎn)真正的處理工作委托給了BeanDefinitionParserDelegate,方法parseBeanDefinitionElement將一個(gè)bean節(jié)點(diǎn)轉(zhuǎn)換成一個(gè)BeanDefinitionHolder對(duì)象,這才是最終的解析過(guò)程;
e. DefaultListableBeanFactory.registerBeanDefinition利用解析好的beanDefinition對(duì)象完成最終的注冊(cè),其實(shí)就是把beanName和beanDefinition作為鍵值對(duì)放到beanFactory對(duì)象的map;
(3) 實(shí)例化Bean
StudentBean bean = (StudentBean)bf.getBean("studentBean");
這一步Spring同樣做了復(fù)雜的處理,但基本原理就是利用反射機(jī)制,通過(guò)bean的class屬性創(chuàng)建一個(gè)bean的實(shí)例,例子中是創(chuàng)建了一個(gè)StudentBean對(duì)象。(4) 調(diào)用對(duì)象的方法,沒什么好說(shuō)的。當(dāng)然如果方法上做了事務(wù)、AOP之類的聲明,這一步的處理就不會(huì)那么簡(jiǎn)單了。
3. 解析配置文件并注冊(cè)bin對(duì)象
我們分析bean的注冊(cè)過(guò)程,就是下面這行代碼,他完成了配置文件的解析和bin的注冊(cè)功能,我們看看Spring到底為我們做了多少事情。
XmlBeanFactory bf = new XmlBeanFactory(res);
public class XmlBeanFactory extends DefaultListableBeanFactory {
//這里為容器定義了一個(gè)默認(rèn)使用的bean定義讀取器
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
//在初始化函數(shù)中使用讀取器來(lái)對(duì)資源進(jìn)行讀取,得到bean定義信息。
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
//這里為容器定義了一個(gè)默認(rèn)使用的bean定義讀取器
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
//在初始化函數(shù)中使用讀取器來(lái)對(duì)資源進(jìn)行讀取,得到bean定義信息。
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
我們跟進(jìn)去,發(fā)現(xiàn)他實(shí)際調(diào)用了XmlBeanDefinitionReader對(duì)象的loadBeanDefinitions方法。
3.1 XmlBeanDefinitionReader.loadBeanDefinitionspublic int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
//封裝資源文件
return loadBeanDefinitions(new EncodedResource(resource));
}
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
//封裝資源文件
return loadBeanDefinitions(new EncodedResource(resource));
}
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
這個(gè)方法是整個(gè)資源加載的切入點(diǎn),我們先大致看看這個(gè)方法的處理流程:
a. 封裝資源文件
new EncodedResource(resource)
b. 獲取輸入流
從EncodedResource對(duì)象中獲取InputStream并構(gòu)造InputSource對(duì)象
c. 然后調(diào)用doLoadBeanDefinitions方法完成具體的加載過(guò)程
new EncodedResource(resource)
b. 獲取輸入流
從EncodedResource對(duì)象中獲取InputStream并構(gòu)造InputSource對(duì)象
c. 然后調(diào)用doLoadBeanDefinitions方法完成具體的加載過(guò)程
3.2 doLoadBeanDefinitions方法
int validationMode = getValidationModeForResource(resource);
Document doc = this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
return registerBeanDefinitions(doc, resource);
這個(gè)方法的代碼很長(zhǎng),如果不考慮異常處理,其實(shí)只做了三件事情:Document doc = this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
return registerBeanDefinitions(doc, resource);
a. 獲取對(duì)XML文件的驗(yàn)證模式
b. 加載XML文件,并得到對(duì)應(yīng)的Document對(duì)象
c. 根據(jù)返回的Document對(duì)象注冊(cè)bean信息
b. 加載XML文件,并得到對(duì)應(yīng)的Document對(duì)象
c. 根據(jù)返回的Document對(duì)象注冊(cè)bean信息
這里對(duì)驗(yàn)證模式不進(jìn)行討論;
這里不對(duì)Document對(duì)象的加載過(guò)程進(jìn)行討論;
這里直接進(jìn)入bean的注冊(cè)方法registerBeanDefinitions
3.3 registerBeanDefinitions方法
這里不對(duì)Document對(duì)象的加載過(guò)程進(jìn)行討論;
這里直接進(jìn)入bean的注冊(cè)方法registerBeanDefinitions
3.3 registerBeanDefinitions方法
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 這里定義解析器,使用XmlBeanDefinitionParser來(lái)解析xml方式的bean定義文件 - 現(xiàn)在的版本不用這個(gè)解析器了,使用的是XmlBeanDefinitionReader
if (this.parserClass != null) {
XmlBeanDefinitionParser parser =
(XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass);
return parser.registerBeanDefinitions(this, doc, resource);
}
// 具體的注冊(cè)過(guò)程,首先得到XmlBeanDefinitionReader,來(lái)處理xml的bean定義文件
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getBeanFactory().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getBeanFactory().getBeanDefinitionCount() - countBefore;
}
// 這里定義解析器,使用XmlBeanDefinitionParser來(lái)解析xml方式的bean定義文件 - 現(xiàn)在的版本不用這個(gè)解析器了,使用的是XmlBeanDefinitionReader
if (this.parserClass != null) {
XmlBeanDefinitionParser parser =
(XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass);
return parser.registerBeanDefinitions(this, doc, resource);
}
// 具體的注冊(cè)過(guò)程,首先得到XmlBeanDefinitionReader,來(lái)處理xml的bean定義文件
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getBeanFactory().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getBeanFactory().getBeanDefinitionCount() - countBefore;
}
當(dāng)把文檔轉(zhuǎn)換為Document對(duì)象后,提取及注冊(cè)bean就是我們的重頭戲了。
這里并沒有看到我們想要的代碼,而是把工作委托給了BeanDefinitionDocumentReader對(duì)象去處理
3.4 BeanDefinitionDocumentReader.doRegisterBeanDefinitions方法這里并沒有看到我們想要的代碼,而是把工作委托給了BeanDefinitionDocumentReader對(duì)象去處理
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
Element root = doc.getDocumentElement();
BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
preProcessXml(root);
parseBeanDefinitions(root, delegate);
postProcessXml(root);
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root.getNamespaceURI())) {
//這里得到xml文件的子節(jié)點(diǎn),比如各個(gè)bean節(jié)點(diǎn)
NodeList nl = root.getChildNodes();
//這里對(duì)每個(gè)節(jié)點(diǎn)進(jìn)行分析處理
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
String namespaceUri = ele.getNamespaceURI();
if (delegate.isDefaultNamespace(namespaceUri)) {
//這里是解析過(guò)程的調(diào)用,對(duì)缺省的元素進(jìn)行分析比如bean元素
parseDefaultElement(ele, delegate);
}else {
delegate.parseCustomElement(ele);
}
}
}
} else {
delegate.parseCustomElement(root);
}
}
this.readerContext = readerContext;
Element root = doc.getDocumentElement();
BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
preProcessXml(root);
parseBeanDefinitions(root, delegate);
postProcessXml(root);
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root.getNamespaceURI())) {
//這里得到xml文件的子節(jié)點(diǎn),比如各個(gè)bean節(jié)點(diǎn)
NodeList nl = root.getChildNodes();
//這里對(duì)每個(gè)節(jié)點(diǎn)進(jìn)行分析處理
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
String namespaceUri = ele.getNamespaceURI();
if (delegate.isDefaultNamespace(namespaceUri)) {
//這里是解析過(guò)程的調(diào)用,對(duì)缺省的元素進(jìn)行分析比如bean元素
parseDefaultElement(ele, delegate);
}else {
delegate.parseCustomElement(ele);
}
}
}
} else {
delegate.parseCustomElement(root);
}
}
經(jīng)過(guò)艱難險(xiǎn)阻,山路十八彎,我們終于走到了核心邏輯的底部doRegisterBeanDefinitions,如果說(shuō)以前一直是XML加載解析的準(zhǔn)備階段,
那么這個(gè)方法算是真正地開始進(jìn)行解析了,我們期待的核心部分真正開始了。
那么這個(gè)方法算是真正地開始進(jìn)行解析了,我們期待的核心部分真正開始了。
這個(gè)方法的代碼我們比較熟悉,讀取Document對(duì)象,循環(huán)每一個(gè)bean節(jié)點(diǎn),然后進(jìn)行處理。
Spring有兩類Bean,一個(gè)是默認(rèn)的,一個(gè)是自定義的bean,這個(gè)方法對(duì)他們分別調(diào)用了不同方法進(jìn)行處理。
3.5 對(duì)默認(rèn)標(biāo)簽的處理 processBeanDefinition方法Spring有兩類Bean,一個(gè)是默認(rèn)的,一個(gè)是自定義的bean,這個(gè)方法對(duì)他們分別調(diào)用了不同方法進(jìn)行處理。
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
a. 首先利用委托類的parseBeanDefinitionElement方法進(jìn)行元素解析,返回BeanDefinitionHolder對(duì)象bdHolder,經(jīng)過(guò)這個(gè)方法,bdHolder實(shí)例已經(jīng)包含我們配置文件中對(duì)bean的所有配置信息了,如name、class等。
b. 對(duì)bdHolder進(jìn)行裝飾
c. 解析完成后,要對(duì)bdHolder進(jìn)行注冊(cè),同樣,注冊(cè)過(guò)程委托給了BeanDefinitionReaderUtils去處理
3.6 delegate.parseBeanDefinitionElement(ele)b. 對(duì)bdHolder進(jìn)行裝飾
c. 解析完成后,要對(duì)bdHolder進(jìn)行注冊(cè),同樣,注冊(cè)過(guò)程委托給了BeanDefinitionReaderUtils去處理
這個(gè)方法便是對(duì)默認(rèn)標(biāo)簽解析的全過(guò)程了,他將一個(gè)element節(jié)點(diǎn)轉(zhuǎn)換成BeanDefinitionsHolder對(duì)象,其中ele和bdHolder中的屬性是對(duì)應(yīng)的。不論是常用的還是不常用的我們都看到了,盡管有些復(fù)雜屬性還需要進(jìn)一步解析,但絲毫不會(huì)影響我們興奮的心情。
a. 提取元素的id和name屬性
b. 進(jìn)一步解析其他所有屬性并統(tǒng)一封裝到BeanDefinition類型的實(shí)例
c. 將獲取到的信息封裝到BeanDefinitionHolder實(shí)例中待續(xù)。。。
b. 進(jìn)一步解析其他所有屬性并統(tǒng)一封裝到BeanDefinition類型的實(shí)例
c. 將獲取到的信息封裝到BeanDefinitionHolder實(shí)例中待續(xù)。。。
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);


AbstractBeanDefinition bd = createBeanDefinition(className, parent);
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
parseConstructorArgElements(ele, bd);
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);
return new BeanDefinitionHolder(bd, beanName, aliasesArray);
跟進(jìn)去,我們就看到解析的最底層了,如parseMetaElements,這里不再進(jìn)行往下分析。String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);


AbstractBeanDefinition bd = createBeanDefinition(className, parent);
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
parseConstructorArgElements(ele, bd);
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);
return new BeanDefinitionHolder(bd, beanName, aliasesArray);
對(duì)于配置文件,解析也解析完了,裝飾也裝飾完了,已經(jīng)把xml中bean元素的各屬性封裝到了BeanDefinition對(duì)象,已經(jīng)可以滿足后續(xù)的使用要求了,剩下的工作便是注冊(cè)解析的BeanDefinition。
這個(gè)方法并沒有做太多事情,而是直接調(diào)用了BeanDefinitionRegistry的注冊(cè)方法。BeanDefinitionRegistry是一個(gè)接口,有多個(gè)實(shí)現(xiàn)類,這里我們使用了默認(rèn)的實(shí)現(xiàn)DefaultListableBeanFactory。
3.8 DefaultListableBeanFactory.registerBeanDefinition代碼啰嗦了一大堆,實(shí)際上所謂的注冊(cè),就是把beanName和beanDefinition對(duì)象作為鍵值對(duì)放到BeanFactory對(duì)象的beanDefinitionMap。
但Spring經(jīng)常把簡(jiǎn)單的邏輯寫的非常“啰嗦”,仔細(xì)分析代碼,發(fā)現(xiàn)他完成了幾個(gè)事情:
a. 對(duì)bean對(duì)象的校驗(yàn)
b. 檢查beanFactory中是否已經(jīng)有同名的bean,如果有,進(jìn)行相應(yīng)處理
c. 把bean對(duì)象放到beanDefinitionMap中(這就是最終所謂的注冊(cè))
d. 清除整個(gè)過(guò)程緩存的對(duì)象數(shù)據(jù)
以上便是Spring對(duì)bean解析注冊(cè)的全過(guò)程,總結(jié)一下大致步驟:
1. 加載XML文件,封裝成Resource對(duì)象
2. 調(diào)用Reader對(duì)象方法讀取XML文件內(nèi)容,并將相關(guān)屬性放到BeanDefinition實(shí)例
3. 將BeanDefinition對(duì)象放到BeanFactory對(duì)象
但Spring經(jīng)常把簡(jiǎn)單的邏輯寫的非常“啰嗦”,仔細(xì)分析代碼,發(fā)現(xiàn)他完成了幾個(gè)事情:
a. 對(duì)bean對(duì)象的校驗(yàn)
b. 檢查beanFactory中是否已經(jīng)有同名的bean,如果有,進(jìn)行相應(yīng)處理
c. 把bean對(duì)象放到beanDefinitionMap中(這就是最終所謂的注冊(cè))
d. 清除整個(gè)過(guò)程緩存的對(duì)象數(shù)據(jù)
以上便是Spring對(duì)bean解析注冊(cè)的全過(guò)程,總結(jié)一下大致步驟:
1. 加載XML文件,封裝成Resource對(duì)象
2. 調(diào)用Reader對(duì)象方法讀取XML文件內(nèi)容,并將相關(guān)屬性放到BeanDefinition實(shí)例
3. 將BeanDefinition對(duì)象放到BeanFactory對(duì)象
4. 實(shí)例化bean
詳細(xì)過(guò)程,預(yù)留位置