本篇將對(duì)定義在 XMl 文件中的 bean,從靜態(tài)的的定義到變成可以使用的對(duì)象的過(guò)程,即 bean 的加載和獲取的過(guò)程進(jìn)行一個(gè)整體的了解,不去深究,點(diǎn)到為止,只求對(duì) Spring IOC 的實(shí)現(xiàn)過(guò)程有一個(gè)整體的感知,具體實(shí)現(xiàn)細(xì)節(jié)留到后面用針對(duì)性的篇章進(jìn)行講解。
首先我們來(lái)引入一個(gè) Spring 入門使用示例,假設(shè)我們現(xiàn)在定義了一個(gè)類 org.zhenchao.framework.MyBean
,我們希望利用 Spring 來(lái)管理類對(duì)象,這里我們利用 Spring 經(jīng)典的 XMl 配置文件形式進(jìn)行配置:
1
2
3
4
5
6
7
8
9
|
<? xml version = "1.0" encoding = "UTF-8" ?> < beansxmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" > <!-- bean的基本配置 --> < beanname = "myBean" class = "org.zhenchao.framework.MyBean" /> </ beans > |
我們將上面的配置文件命名為 spring-core.xml,則對(duì)象的最原始的獲取和使用示例如下:
1
2
3
4
5
6
7
8
|
// 1. 定義資源 Resource resource = new ClassPathResource( "spring-core.xml" ); // 2. 利用XmlBeanFactory解析并注冊(cè)bean定義 XmlBeanFactory beanFactory = new XmlBeanFactory(resource); // 3. 從IOC容器加載獲取bean MyBean myBean = (MyBean) beanFactory.getBean( "myBean" ); // 4. 使用bean myBean.sayHello(); |
上面 demo 雖然簡(jiǎn)單,但麻雀雖小,五臟俱全,完整的讓 Spring 執(zhí)行了一遍配置文件加載,并獲取 bean 的過(guò)程。雖然從 Spring 3.1 開始 XmlBeanFactory 已經(jīng)被置為 Deprecated
,但是 Spring 并沒有定義出更加高級(jí)的基于 XML 加載 bean 的 BeanFactory,而是推薦采用更加原生的方式,即組合使用 DefaultListableBeanFactory
和 XmlBeanDefinitionReader
來(lái)完成上訴過(guò)程:
1
2
3
4
5
6
|
Resource resource = new ClassPathResource( "spring-core.xml" ); DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); reader.loadBeanDefinitions(resource); MyBean myBean = (MyBean) beanFactory.getBean( "myBean" ); myBean.sayHello(); |
后面的分析你將會(huì)看到 XmlBeanFactory 實(shí)際上是對(duì) DefaultListableBeanFactory 和 XmlBeanDefinitionReader 組合使用方式的封裝,所以這里我們?nèi)匀粚⒗^續(xù)分析基于 XmlBeanFactory 加載 bean 的過(guò)程。
一. Bean的解析和注冊(cè)
Bean的加載過(guò)程,主要是對(duì)配置文件的解析,并注冊(cè) bean 的過(guò)程,上圖是加載過(guò)程的時(shí)序圖,當(dāng)我們 new XmlBeanFactory(resource)
的時(shí)候,已經(jīng)完成將配置文件包裝成了 Spring 定義的資源,并觸發(fā)解析和注冊(cè)。 new XmlBeanFactory(resource)
調(diào)用的是下面的構(gòu)造方法:
1
2
3
|
publicXmlBeanFactory(Resource resource)throwsBeansException{ this (resource, null ); } |
這個(gè)構(gòu)造方法本質(zhì)上還是繼續(xù)調(diào)用了:
1
2
3
4
5
|
publicXmlBeanFactory(Resource resource, BeanFactory parentBeanFactory)throwsBeansException{ super (parentBeanFactory); // 加載xml資源 this .reader.loadBeanDefinitions(resource); } |
在這個(gè)構(gòu)造方法里面先是調(diào)用了父類構(gòu)造函數(shù),即 org.springframework.beans.factory.support.DefaultListableBeanFactory
類,這是一個(gè)非常核心的類,它包含了基本 IOC 容器所具有的重要功能,是一個(gè) IOC 容器的基本實(shí)現(xiàn)。然后是調(diào)用了 this.reader.loadBeanDefinitions(resource)
,從這里開始加載配置文件。
Spring 在設(shè)計(jì)采用了許多程序設(shè)計(jì)的基本原則,比如迪米特法則、開閉原則,以及接口隔離原則等等,這樣的設(shè)計(jì)為后續(xù)的擴(kuò)展提供了靈活性,也增強(qiáng)了模塊的復(fù)用性,這也是我看 Spring 源碼的動(dòng)力之一,希望通過(guò)閱讀學(xué)習(xí)的過(guò)程來(lái)提升自己接口設(shè)計(jì)的能力。Spring 使用了專門的資源加載器對(duì)資源進(jìn)行加載,這里的 reader 就是 org.springframework.beans.factory.xml.XmlBeanDefinitionReader
對(duì)象,專門用來(lái)加載基于 XML 文件配置的 bean。這里的加載過(guò)程為:
- 利用 EncodedResource 二次包裝資源文件
- 獲取資源輸入流,并構(gòu)造 InputSource 對(duì)象
- 獲取 XML 文件的實(shí)體解析器和驗(yàn)證模式
- 加載 XML 文件,獲取對(duì)應(yīng)的 Document 對(duì)象
- 由 Document 對(duì)象解析并注冊(cè) bean
1.利用 EncodedResource 二次包裝資源文件
采用 org.springframework.core.io.support.EncodedResource 對(duì)resource 進(jìn)行二次封裝.
2.獲取資源輸入流,并構(gòu)造 InputSource 對(duì)象
對(duì)資源進(jìn)行編碼封裝之后,開始真正進(jìn)入 this.loadBeanDefinitions(new EncodedResource(resource)) 的過(guò)程,該方法源碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
publicintloadBeanDefinitions(EncodedResource encodedResource)throwsBeanDefinitionStoreException{ Assert.notNull(encodedResource, "EncodedResource must not be null" ); if (logger.isInfoEnabled()) { logger.info( "Loading XML bean definitions from " + encodedResource.getResource()); } // 標(biāo)記正在加載的資源,防止循環(huán)引用 Set<EncodedResource> currentResources = this .resourcesCurrentlyBeingLoaded.get(); if (currentResources == null ) { currentResources = new HashSet<EncodedResource>( 4 ); this .resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!" ); } try { // 獲取資源的輸入流 InputStream inputStream = encodedResource.getResource().getInputStream(); try { // 構(gòu)造InputSource對(duì)象 InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null ) { inputSource.setEncoding(encodedResource.getEncoding()); } // 真正開始從XML文件中加載Bean定義 return this .doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this .resourcesCurrentlyBeingLoaded.remove(); } } } |
需要知曉的是 org.xml.sax.InputSource
不是 Spring 中定義的類,這個(gè)類來(lái)自 jdk,是 java 對(duì) XML 實(shí)體提供的原生支持。這個(gè)方法主要還是做了一些準(zhǔn)備工作,按照 Spring 方法的命名相關(guān),真正干活的方法一般都是以 “do” 開頭的,這里的 this.doLoadBeanDefinitions(inputSource, encodedResource.getResource())
就是真正開始加載 XMl 的入口,該方法源碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
protectedintdoLoadBeanDefinitions(InputSource inputSource, Resource resource)throwsBeanDefinitionStoreException{ try { // 1. 加載xml文件,獲取到對(duì)應(yīng)的Document(包含獲取xml文件的實(shí)體解析器和驗(yàn)證模式) Document doc = this .doLoadDocument(inputSource, resource); // 2. 解析Document對(duì)象,并注冊(cè)bean return this .registerBeanDefinitions(doc, resource); } catch (BeanDefinitionStoreException ex) { // 這里是連環(huán)catch,省略 } } |
方面里面的邏輯還是很清晰的,第一步獲取 org.w3c.dom.Document 對(duì)象,第二步由該對(duì)象解析得到 BeanDefinition 對(duì)象,并注冊(cè)到 IOC 容器中。
3.獲取 XML 文件的實(shí)體解析器和驗(yàn)證模式
this.doLoadDocument(inputSource, resource)
包含了獲取實(shí)體解析器、驗(yàn)證模式,以及 Document 對(duì)象的邏輯,源碼如下:
1
2
3
4
5
6
7
8
|
protectedDocumentdoLoadDocument(InputSource inputSource, Resource resource)throwsException{ return this .documentLoader.loadDocument( inputSource, this .getEntityResolver(), // 獲取實(shí)體解析器 this .errorHandler, this .getValidationModeForResource(resource), // 獲取驗(yàn)證模式 this .isNamespaceAware()); } |
XML 是半結(jié)構(gòu)化數(shù)據(jù),XML 的驗(yàn)證模式用于保證結(jié)構(gòu)的正確性,常見的驗(yàn)證模式有 DTD 和 XSD 兩種,獲取驗(yàn)證模式的源碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
protectedintgetValidationModeForResource(Resource resource){ int validationModeToUse = this .getValidationMode(); if (validationModeToUse != VALIDATION_AUTO) { // 手動(dòng)指定了驗(yàn)證模式 return validationModeToUse; } // 沒有指定驗(yàn)證模式,則自動(dòng)檢測(cè) int detectedMode = this .detectValidationMode(resource); if (detectedMode != VALIDATION_AUTO) { return detectedMode; } // 檢測(cè)驗(yàn)證模式失敗,默認(rèn)采用XSD驗(yàn)證 return VALIDATION_XSD; } |
上面源碼描述了獲取驗(yàn)證模式的執(zhí)行流程,如果沒有手動(dòng)指定,那么 Spring 會(huì)去自動(dòng)檢測(cè)。對(duì)于 XML 文件的解析,SAX 首先會(huì)讀取 XML 文件頭聲明,以獲取對(duì)應(yīng)驗(yàn)證文件地址,并下載對(duì)應(yīng)的文件,如果網(wǎng)絡(luò)不正常,則會(huì)影響下載過(guò)程,這個(gè)時(shí)候可以通過(guò)注冊(cè)一個(gè)實(shí)體解析來(lái)實(shí)現(xiàn)尋找驗(yàn)證文件的過(guò)程。
4.加載 XML 文件,獲取對(duì)應(yīng)的 Document 對(duì)象
獲取對(duì)應(yīng)的驗(yàn)證模式和解析器,解析去就可以加載 Document 對(duì)象了,這里本質(zhì)上調(diào)用的是 org.springframework.beans.factory.xml.DefaultDocumentLoader
的 loadDocument() 方法,源碼如下:
1
2
3
4
5
6
7
8
9
10
|
publicDocumentloadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception { DocumentBuilderFactory factory = this .createDocumentBuilderFactory(validationMode, namespaceAware); if (logger.isDebugEnabled()) { logger.debug( "Using JAXP provider [" + factory.getClass().getName() + "]" ); } DocumentBuilder builder = this .createDocumentBuilder(factory, entityResolver, errorHandler); return builder.parse(inputSource); } |
整個(gè)過(guò)程類似于我們平常解析 XML 文件的流程。
5.由 Document 對(duì)象解析并注冊(cè) bean
完成了對(duì) XML 文件的到 Document 對(duì)象的解析,我們終于可以解析 Document 對(duì)象,并注冊(cè) bean 了,這一過(guò)程發(fā)生在 this.registerBeanDefinitions(doc, resource)
中,源碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
publicintregisterBeanDefinitions(Document doc, Resource resource)throwsBeanDefinitionStoreException{ // 使用DefaultBeanDefinitionDocumentReader構(gòu)造 BeanDefinitionDocumentReader documentReader = this .createBeanDefinitionDocumentReader(); // 記錄之前已經(jīng)注冊(cè)的BeanDefinition個(gè)數(shù) int countBefore = this .getRegistry().getBeanDefinitionCount(); // 加載并注冊(cè)bean documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); // 返回本次加載的bean的數(shù)量 return getRegistry().getBeanDefinitionCount() - countBefore; } |
這里方法的作用是創(chuàng)建對(duì)應(yīng)的 BeanDefinitionDocumentReader,并計(jì)算返回了過(guò)程中新注冊(cè)的 bean 的數(shù)量,而具體的注冊(cè)過(guò)程,則是由 BeanDefinitionDocumentReader 來(lái)完成的,具體的實(shí)現(xiàn)位于子類 DefaultBeanDefinitionDocumentReader 中:
1
2
3
4
5
6
7
8
9
|
publicvoidregisterBeanDefinitions(Document doc, XmlReaderContext readerContext){ this .readerContext = readerContext; logger.debug( "Loading bean definitions" ); // 獲取文檔的root結(jié)點(diǎn) Element root = doc.getDocumentElement(); this .doRegisterBeanDefinitions(root); } |
還是按照 Spring 命名習(xí)慣,doRegisterBeanDefinitions 才是真正干活的地方,這也是真正開始解析配置的核心所在:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
protectedvoiddoRegisterBeanDefinitions(Element root){ BeanDefinitionParserDelegate parent = this .delegate; this .delegate = this .createDelegate(getReaderContext(), root, parent); if ( this .delegate.isDefaultNamespace(root)) { // 處理profile標(biāo)簽(其作用類比pom.xml中的profile) String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (! this .getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isInfoEnabled()) { logger.info( "Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return ; } } } // 解析預(yù)處理,留給子類實(shí)現(xiàn) this .preProcessXml(root); // 解析并注冊(cè)BeanDefinition this .parseBeanDefinitions(root, this .delegate); // 解析后處理,留給子類實(shí)現(xiàn) this .postProcessXml(root); this .delegate = parent; } |
方法中顯示處理了 標(biāo)簽,這個(gè)屬性在 Spring 中不是很常用,不過(guò)在 maven 的 pom.xml 中則很常見,意義也是相同的,就是配置多套環(huán)境,從而在部署的時(shí)候可以根據(jù)具體環(huán)境來(lái)選擇使用哪一套配置。方法中會(huì)先去檢測(cè)是否配置了 profile,如果配置了就需要從上下文環(huán)境中確認(rèn)當(dāng)前激活了哪一套 profile。
方法在解析并注冊(cè) BeanDefinition 前后各設(shè)置一個(gè)模板方法,留給子類擴(kuò)展實(shí)現(xiàn),而在 this.parseBeanDefinitions(root, this.delegate)
中執(zhí)行解析和注冊(cè)邏輯:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
protectedvoidparseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate){ if (delegate.isDefaultNamespace(root)) { // 解析默認(rèn)標(biāo)簽 NodeList nl = root.getChildNodes(); for ( int i = 0 ; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { // 解析默認(rèn)標(biāo)簽 this .parseDefaultElement(ele, delegate); } else { // 解析自定義標(biāo)簽 delegate.parseCustomElement(ele); } } } } else { // 解析自定義標(biāo)簽 delegate.parseCustomElement(root); } } |
方法中判斷當(dāng)前標(biāo)簽是默認(rèn)標(biāo)簽還是自定義標(biāo)簽,并按照不同的策略去解析,這是一個(gè)復(fù)雜的過(guò)程,后面用文章進(jìn)行針對(duì)性講解,這里不在往下細(xì)究。
到這里我們已經(jīng)完成了靜態(tài)配置到動(dòng)態(tài) BeanDefinition 的解析,這個(gè)時(shí)候 bean 的定義已經(jīng)處于內(nèi)存中,解析去將是探究如何獲取并使用 bean 的過(guò)程。
二. Bean的獲取
在完成了 Bean 的加載過(guò)程之后,我們可以調(diào)用 beanFactory.getBean("myBean")
方法來(lái)獲取目標(biāo)對(duì)象,這里本質(zhì)上調(diào)用的是 org.springframework.beans.factory.support.AbstractBeanFactory
的 getBean() 方法,源碼如下:
1
2
3
|
publicObjectgetBean(String name)throwsBeansException{ return this .doGetBean(name, null , null , false ); } |
這里調(diào)用 this.doGetBean(name, null, null, false)
來(lái)實(shí)現(xiàn)具體邏輯,也符合我們的預(yù)期,該方法可以看做是獲取 bean 的整體框架,一個(gè)函數(shù)完成了整個(gè)過(guò)程的模塊調(diào)度,還是挺復(fù)雜的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
protected <T> TdoGetBean( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { /* * 轉(zhuǎn)化對(duì)應(yīng)的beanName * * 傳入的參數(shù)可能是alias,也可能是FactoryBean,所以需要進(jìn)行解析,主要包含以下內(nèi)容: * 1. 去除FactoryBean的修飾符“&” * 2. 取指定alias對(duì)應(yīng)的最終的name */ final String beanName = this.transformedBeanName(name); Object bean; /* * 檢查緩存或者實(shí)例工廠中是否有對(duì)應(yīng)的實(shí)例 * * 為什么會(huì)一開始就進(jìn)行檢查? * 因?yàn)樵趧?chuàng)建單例bean的時(shí)候會(huì)存在依賴注入的情況,而在創(chuàng)建依賴的時(shí)候?yàn)榱吮苊庋h(huán)依賴 * Spring創(chuàng)建bean的原則是不等bean創(chuàng)建完成就會(huì)將創(chuàng)建bean的ObjectFactory提前曝光,即將對(duì)應(yīng)的ObjectFactory加入到緩存 * 一旦下一個(gè)bean創(chuàng)建需要依賴上一個(gè)bean,則直接使用ObjectFactory */ Object sharedInstance = this.getSingleton(beanName); // 獲取單例 if (sharedInstance != null && args == null) { // 實(shí)例已經(jīng)存在 if (logger.isDebugEnabled()) { if (this.isSingletonCurrentlyInCreation(beanName)) { logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.debug("Returning cached instance of singleton bean '" + beanName + "'"); } } // 返回對(duì)應(yīng)的實(shí)例 bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { // 單例實(shí)例不存在 if (this.isPrototypeCurrentlyInCreation(beanName)) { /* * 只有在單例模式下才會(huì)嘗試解決循環(huán)依賴問(wèn)題 * 對(duì)于原型模式,如果存在循環(huán)依賴,也就是滿足this.isPrototypeCurrentlyInCreation(beanName),拋出異常 */ throw new BeanCurrentlyInCreationException(beanName); } BeanFactory parentBeanFactory = this.getParentBeanFactory(); if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) { // 如果在beanDefinitionMap中(即所有已經(jīng)加載的類中)不包含目標(biāo)bean,則嘗試從parentBeanFactory中檢測(cè) String nameToLookup = this.originalBeanName(name); if (args != null) { // 遞歸到BeanFactory中尋找 return (T) parentBeanFactory.getBean(nameToLookup, args); } else { return parentBeanFactory.getBean(nameToLookup, requiredType); } } // 如果不僅僅是做類型檢查,則創(chuàng)建bean if (!typeCheckOnly) { this.markBeanAsCreated(beanName); } try { /* * 將存儲(chǔ)XML配置的GenericBeanDefinition轉(zhuǎn)換成RootBeanDefinition * 如果指定了beanName是子bean的話,同時(shí)會(huì)合并父類的相關(guān)屬性 */ final RootBeanDefinition mbd = this .getMergedLocalBeanDefinition(beanName); this .checkMergedBeanDefinition(mbd, beanName, args); // 獲取當(dāng)前bean依賴的bean String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null ) { // 存在依賴,遞歸實(shí)例化依賴的bean for (String dep : dependsOn) { if ( this .isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'" ); } // 緩存依賴調(diào)用 this .registerDependentBean(dep, beanName); this .getBean(dep); } } // 實(shí)例化依賴的bean后,實(shí)例化mbd自身 if (mbd.isSingleton()) { // scope == singleton sharedInstance = this .getSingleton(beanName, new ObjectFactory<Object>() { @Override publicObjectgetObject()throwsBeansException{ try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } } }); bean = this .getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } else if (mbd.isPrototype()) { // scope == prototype Object prototypeInstance; try { this .beforePrototypeCreation(beanName); prototypeInstance = this .createBean(beanName, mbd, args); } finally { this .afterPrototypeCreation(beanName); } // 返回對(duì)應(yīng)的實(shí)例 bean = this .getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { // 其它scope String scopeName = mbd.getScope(); final Scope scope = this .scopes.get(scopeName); if (scope == null ) { throw new IllegalStateException( "No Scope registered for scope name '" + scopeName + "'" ); } try { Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() { @Override publicObjectgetObject()throwsBeansException{ beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } } }); // 返回對(duì)應(yīng)的實(shí)例 bean = this .getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton" , ex); } } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } // 檢查需要的類型是否符合bean的實(shí)際類型,對(duì)應(yīng)getBean時(shí)指定的requireType if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) { try { return this .getTypeConverter().convertIfNecessary(bean, requiredType); } catch (TypeMismatchException ex) { if (logger.isDebugEnabled()) { logger.debug( "Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'" , ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } return (T) bean; } |
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:http://www.zhenchao.org/2017/05/10/spring-src-bean-factory/?utm_source=tuicool&utm_medium=referral