一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - 詳解Spring簡單容器中的Bean基本加載過程

詳解Spring簡單容器中的Bean基本加載過程

2020-09-29 10:56指 間 生 活 Java教程

本篇將對定義在 XMl 文件中的 bean,從靜態(tài)的的定義到變成可以使用的對象的過程,即 bean 的加載和獲取的過程進(jìn)行一個整體的了解

本篇將對定義在 XMl 文件中的 bean,從靜態(tài)的的定義到變成可以使用的對象的過程,即 bean 的加載和獲取的過程進(jìn)行一個整體的了解,不去深究,點(diǎn)到為止,只求對 Spring IOC 的實(shí)現(xiàn)過程有一個整體的感知,具體實(shí)現(xiàn)細(xì)節(jié)留到后面用針對性的篇章進(jìn)行講解。

首先我們來引入一個 Spring 入門使用示例,假設(shè)我們現(xiàn)在定義了一個類 org.zhenchao.framework.MyBean ,我們希望利用 Spring 來管理類對象,這里我們利用 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,則對象的最原始的獲取和使用示例如下:

?
1
2
3
4
5
6
7
8
// 1. 定義資源
Resource resource = new ClassPathResource("spring-core.xml");
// 2. 利用XmlBeanFactory解析并注冊bean定義
XmlBeanFactory beanFactory = new XmlBeanFactory(resource);
// 3. 從IOC容器加載獲取bean
MyBean myBean = (MyBean) beanFactory.getBean("myBean");
// 4. 使用bean
myBean.sayHello();

上面 demo 雖然簡單,但麻雀雖小,五臟俱全,完整的讓 Spring 執(zhí)行了一遍配置文件加載,并獲取 bean 的過程。雖然從 Spring 3.1 開始 XmlBeanFactory 已經(jīng)被置為 Deprecated ,但是 Spring 并沒有定義出更加高級的基于 XML 加載 bean 的 BeanFactory,而是推薦采用更加原生的方式,即組合使用 DefaultListableBeanFactory XmlBeanDefinitionReader 來完成上訴過程:

?
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();

后面的分析你將會看到 XmlBeanFactory 實(shí)際上是對 DefaultListableBeanFactory 和 XmlBeanDefinitionReader 組合使用方式的封裝,所以這里我們?nèi)匀粚⒗^續(xù)分析基于 XmlBeanFactory 加載 bean 的過程。

一. Bean的解析和注冊

詳解Spring簡單容器中的Bean基本加載過程

Bean的加載過程,主要是對配置文件的解析,并注冊 bean 的過程,上圖是加載過程的時序圖,當(dāng)我們 new XmlBeanFactory(resource) 的時候,已經(jīng)完成將配置文件包裝成了 Spring 定義的資源,并觸發(fā)解析和注冊。 new XmlBeanFactory(resource) 調(diào)用的是下面的構(gòu)造方法:

?
1
2
3
publicXmlBeanFactory(Resource resource)throwsBeansException{
  this(resource, null);
}

這個構(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òu)造方法里面先是調(diào)用了父類構(gòu)造函數(shù),即 org.springframework.beans.factory.support.DefaultListableBeanFactory 類,這是一個非常核心的類,它包含了基本 IOC 容器所具有的重要功能,是一個 IOC 容器的基本實(shí)現(xiàn)。然后是調(diào)用了 this.reader.loadBeanDefinitions(resource) ,從這里開始加載配置文件。

Spring 在設(shè)計(jì)采用了許多程序設(shè)計(jì)的基本原則,比如迪米特法則、開閉原則,以及接口隔離原則等等,這樣的設(shè)計(jì)為后續(xù)的擴(kuò)展提供了靈活性,也增強(qiáng)了模塊的復(fù)用性,這也是我看 Spring 源碼的動力之一,希望通過閱讀學(xué)習(xí)的過程來提升自己接口設(shè)計(jì)的能力。Spring 使用了專門的資源加載器對資源進(jìn)行加載,這里的 reader 就是 org.springframework.beans.factory.xml.XmlBeanDefinitionReader 對象,專門用來加載基于 XML 文件配置的 bean。這里的加載過程為:

  1. 利用 EncodedResource 二次包裝資源文件
  2. 獲取資源輸入流,并構(gòu)造 InputSource 對象
  3. 獲取 XML 文件的實(shí)體解析器和驗(yàn)證模式
  4. 加載 XML 文件,獲取對應(yīng)的 Document 對象
  5. 由 Document 對象解析并注冊 bean

1.利用 EncodedResource 二次包裝資源文件

采用 org.springframework.core.io.support.EncodedResource 對resource 進(jìn)行二次封裝.

2.獲取資源輸入流,并構(gòu)造 InputSource 對象

對資源進(jìn)行編碼封裝之后,開始真正進(jìn)入 this.loadBeanDefinitions(new EncodedResource(resource)) 的過程,該方法源碼如下:

?
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對象
      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 中定義的類,這個類來自 jdk,是 java 對 XML 實(shí)體提供的原生支持。這個方法主要還是做了一些準(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文件,獲取到對應(yīng)的Document(包含獲取xml文件的實(shí)體解析器和驗(yàn)證模式)
    Document doc = this.doLoadDocument(inputSource, resource);
 
    // 2. 解析Document對象,并注冊bean
    return this.registerBeanDefinitions(doc, resource);
 
  } catch (BeanDefinitionStoreException ex) {
    // 這里是連環(huán)catch,省略
  }
}

方面里面的邏輯還是很清晰的,第一步獲取 org.w3c.dom.Document 對象,第二步由該對象解析得到 BeanDefinition 對象,并注冊到 IOC 容器中。

3.獲取 XML 文件的實(shí)體解析器和驗(yàn)證模式

this.doLoadDocument(inputSource, resource) 包含了獲取實(shí)體解析器、驗(yàn)證模式,以及 Document 對象的邏輯,源碼如下:

?
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) {
    // 手動指定了驗(yàn)證模式
    return validationModeToUse;
  }
 
  // 沒有指定驗(yàn)證模式,則自動檢測
  int detectedMode = this.detectValidationMode(resource);
  if (detectedMode != VALIDATION_AUTO) {
    return detectedMode;
  }
 
  // 檢測驗(yàn)證模式失敗,默認(rèn)采用XSD驗(yàn)證
  return VALIDATION_XSD;
}

上面源碼描述了獲取驗(yàn)證模式的執(zhí)行流程,如果沒有手動指定,那么 Spring 會去自動檢測。對于 XML 文件的解析,SAX 首先會讀取 XML 文件頭聲明,以獲取對應(yīng)驗(yàn)證文件地址,并下載對應(yīng)的文件,如果網(wǎng)絡(luò)不正常,則會影響下載過程,這個時候可以通過注冊一個實(shí)體解析來實(shí)現(xiàn)尋找驗(yàn)證文件的過程。

4.加載 XML 文件,獲取對應(yīng)的 Document 對象

獲取對應(yīng)的驗(yàn)證模式和解析器,解析去就可以加載 Document 對象了,這里本質(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);
}

整個過程類似于我們平常解析 XML 文件的流程。

5.由 Document 對象解析并注冊 bean

完成了對 XML 文件的到 Document 對象的解析,我們終于可以解析 Document 對象,并注冊 bean 了,這一過程發(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)注冊的BeanDefinition個數(shù)
  int countBefore = this.getRegistry().getBeanDefinitionCount();
 
  // 加載并注冊bean
  documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
 
  // 返回本次加載的bean的數(shù)量
  return getRegistry().getBeanDefinitionCount() - countBefore;
}

這里方法的作用是創(chuàng)建對應(yīng)的 BeanDefinitionDocumentReader,并計(jì)算返回了過程中新注冊的 bean 的數(shù)量,而具體的注冊過程,則是由 BeanDefinitionDocumentReader 來完成的,具體的實(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);
 
  // 解析并注冊BeanDefinition
  this.parseBeanDefinitions(root, this.delegate);
 
  // 解析后處理,留給子類實(shí)現(xiàn)
  this.postProcessXml(root);
 
  this.delegate = parent;
}

方法中顯示處理了 標(biāo)簽,這個屬性在 Spring 中不是很常用,不過在 maven 的 pom.xml 中則很常見,意義也是相同的,就是配置多套環(huán)境,從而在部署的時候可以根據(jù)具體環(huán)境來選擇使用哪一套配置。方法中會先去檢測是否配置了 profile,如果配置了就需要從上下文環(huán)境中確認(rèn)當(dāng)前激活了哪一套 profile。

方法在解析并注冊 BeanDefinition 前后各設(shè)置一個模板方法,留給子類擴(kuò)展實(shí)現(xiàn),而在 this.parseBeanDefinitions(root, this.delegate) 中執(zhí)行解析和注冊邏輯:

?
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)簽,并按照不同的策略去解析,這是一個復(fù)雜的過程,后面用文章進(jìn)行針對性講解,這里不在往下細(xì)究。

到這里我們已經(jīng)完成了靜態(tài)配置到動態(tài) BeanDefinition 的解析,這個時候 bean 的定義已經(jīng)處于內(nèi)存中,解析去將是探究如何獲取并使用 bean 的過程。

二. Bean的獲取

在完成了 Bean 的加載過程之后,我們可以調(diào)用 beanFactory.getBean("myBean") 方法來獲取目標(biāo)對象,這里本質(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) 來實(shí)現(xiàn)具體邏輯,也符合我們的預(yù)期,該方法可以看做是獲取 bean 的整體框架,一個函數(shù)完成了整個過程的模塊調(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)化對應(yīng)的beanName
   *
   * 傳入的參數(shù)可能是alias,也可能是FactoryBean,所以需要進(jìn)行解析,主要包含以下內(nèi)容:
   * 1. 去除FactoryBean的修飾符“&”
   * 2. 取指定alias對應(yīng)的最終的name
   */
  final String beanName = this.transformedBeanName(name);
 
  Object bean;
 
  /*
   * 檢查緩存或者實(shí)例工廠中是否有對應(yīng)的實(shí)例
   *
   * 為什么會一開始就進(jìn)行檢查?
   * 因?yàn)樵趧?chuàng)建單例bean的時候會存在依賴注入的情況,而在創(chuàng)建依賴的時候?yàn)榱吮苊庋h(huán)依賴
   * Spring創(chuàng)建bean的原則是不等bean創(chuàng)建完成就會將創(chuàng)建bean的ObjectFactory提前曝光,即將對應(yīng)的ObjectFactory加入到緩存
   * 一旦下一個bean創(chuàng)建需要依賴上一個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 + "'");
      }
    }
    // 返回對應(yīng)的實(shí)例
    bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, null);
  } else {
    // 單例實(shí)例不存在
    if (this.isPrototypeCurrentlyInCreation(beanName)) {
      /*
       * 只有在單例模式下才會嘗試解決循環(huán)依賴問題
       * 對于原型模式,如果存在循環(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中檢測
      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 {
      /*
       * 將存儲XML配置的GenericBeanDefinition轉(zhuǎn)換成RootBeanDefinition
       * 如果指定了beanName是子bean的話,同時會合并父類的相關(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);
        }
        // 返回對應(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);
              }
            }
          });
          // 返回對應(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í)際類型,對應(yīng)getBean時指定的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;
}

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。

原文鏈接:http://www.zhenchao.org/2017/05/10/spring-src-bean-factory/?utm_source=tuicool&utm_medium=referral

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 91制片厂制作传媒破解版免费 | 国产自在线拍 | 四缺一小说 | 好大用力深一点女公交车 | 亚洲欧美日韩国产一区二区精品 | 九九365资源稳定资源站 | 国产免费视 | 日本美女视频韩国视频网站免费 | 草莓视频网站18勿进 | 欧美一区二区三区四区五区六区 | china国产bbw| 国产精品一久久香蕉产线看 | 欧美国产日本高清不卡 | 国产日本欧美亚洲精品视 | 能播放的欧美同性videos | 国产欧美精品一区二区三区四区 | 大杳蕉在线影院在线播放 | 小夫妻天天恶战 | 久久青青草原精品国产软件 | 国产精品合集一区二区 | 国产区成人精品视频 | 男人的天堂在线观看入口 | 欧美va免费精品高清在线 | 亚洲精品黄色 | 91麻豆国产精品91久久久 | 好男人天堂网 | 欧美一级鲁丝片免费看 | 精品午夜寂寞黄网站在线 | 色一情一区二区三区四区 | 嫩草研究| 阿 好深 快点 老师受不了 | 免费特黄视频 | 欧美一区精品 | 色五婷婷 | 免费在线看a | 白鹿扒开内裤露出尿孔 | 深夜免费在线视频 | 日处女b| 国产趴着打光屁股sp抽打 | 1024免费永久福利视频 | 国产午夜精品一区二区 |