激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

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

服務器之家 - 編程語言 - Java教程 - 詳解Spring循環依賴的解決方案

詳解Spring循環依賴的解決方案

2021-05-05 10:48數齊 Java教程

這篇文章主要介紹了詳解Spring循環依賴的解決方案,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

spring針對bean之間的循環依賴,有自己的處理方案。關鍵點就是三級緩存。當然這種方案不能解決所有的問題,他只能解決bean單例模式下非構造函數的循環依賴。

我們就從a->b->c-a這個初始化順序,也就是a的bean中需要b的實例,b的bean中需要c的實例,c的bean中需要a的實例,當然這種需要不是構造函數那種依賴。前提條件有了,我們就可以開始了。毫無疑問,我們會先初始化a.初始化的方法是org.springframework.beans.factory.support.abstractbeanfactory#dogetbean

?
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
protected <t> t dogetbean(
   final string name, final class<t> requiredtype, final object[] args, boolean typecheckonly)
   throws beansexception {
 
  final string beanname = transformedbeanname(name);
  object bean;
 
  // eagerly check singleton cache for manually registered singletons.
  object sharedinstance = getsingleton(beanname); //關注點1
  if (sharedinstance != null && args == null) {
   if (logger.isdebugenabled()) {
    if (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 + "'");
    }
   }
   bean = getobjectforbeaninstance(sharedinstance, name, beanname, null);
  }
 
  else {
   // fail if we're already creating this bean instance:
   // we're assumably within a circular reference.
   if (isprototypecurrentlyincreation(beanname)) {
    throw new beancurrentlyincreationexception(beanname);
   }
 
   // check if bean definition exists in this factory.
   beanfactory parentbeanfactory = getparentbeanfactory();
   if (parentbeanfactory != null && !containsbeandefinition(beanname)) {
    // not found -> check parent.
    string nametolookup = originalbeanname(name);
    if (args != null) {
     // delegation to parent with explicit args.
     return (t) parentbeanfactory.getbean(nametolookup, args);
    }
    else {
     // no args -> delegate to standard getbean method.
     return parentbeanfactory.getbean(nametolookup, requiredtype);
    }
   }
 
   if (!typecheckonly) {
    markbeanascreated(beanname);
   }
 
   try {
    final rootbeandefinition mbd = getmergedlocalbeandefinition(beanname);
    checkmergedbeandefinition(mbd, beanname, args);
 
    // guarantee initialization of beans that the current bean depends on.
    string[] dependson = mbd.getdependson();
    if (dependson != null) {
     for (string dependsonbean : dependson) {
      if (isdependent(beanname, dependsonbean)) {
       throw new beancreationexception(mbd.getresourcedescription(), beanname,
         "circular depends-on relationship between '" + beanname + "' and '" + dependsonbean + "'");
      }
      registerdependentbean(dependsonbean, beanname);
      getbean(dependsonbean);
     }
    }
 
    // create bean instance.
    if (mbd.issingleton()) {
     //關注點2
     sharedinstance = getsingleton(beanname, new objectfactory<object>() {
      @override
      public object getobject() throws beansexception {
       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 = getobjectforbeaninstance(sharedinstance, name, beanname, mbd);
    }
 
    else if (mbd.isprototype()) {
     // it's a prototype -> create a new instance.
     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);
     if (scope == null) {
      throw new illegalstateexception("no scope registered for scope name '" + scopename + "'");
     }
     try {
      object scopedinstance = scope.get(beanname, new objectfactory<object>() {
       @override
       public object getobject() throws beansexception {
        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 '" + 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;
   }
  }
 
  // check if required type matches the type of the actual bean instance.
  if (requiredtype != null && bean != null && !requiredtype.isassignablefrom(bean.getclass())) {
   try {
    return 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;
 }

這個方法很長我們一點點說。先看我們的關注點1 object sharedinstance = getsingleton(beanname)根據名稱從單例的集合中獲取單例對象,我們看下這個方法,他最終是org.springframework.beans.factory.support.defaultsingletonbeanregistry#getsingleton(java.lang.string, boolean)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protected object getsingleton(string beanname, boolean allowearlyreference) {
 object singletonobject = this.singletonobjects.get(beanname);
 if (singletonobject == null && issingletoncurrentlyincreation(beanname)) {
  synchronized (this.singletonobjects) {
   singletonobject = this.earlysingletonobjects.get(beanname);
   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 != null_object ? singletonobject : null);
}

大家一定要注意這個方法,很關鍵,我們開篇提到了三級緩存,使用點之一就是這里。到底是哪三級緩存呢,第一級緩存singletonobjects里面放置的是實例化好的單例對象。第二級earlysingletonobjects里面存放的是提前曝光的單例對象(沒有完全裝配好)。第三級singletonfactories里面存放的是要被實例化的對象的對象工廠。解釋好了三級緩存,我們再看看邏輯。第一次進來this.singletonobjects.get(beanname)返回的肯定是null。然后issingletoncurrentlyincreation決定了能否進入二級緩存中獲取數據。

?
1
2
3
public boolean issingletoncurrentlyincreation(string beanname) {
  return this.singletonscurrentlyincreation.contains(beanname);
 }

singletonscurrentlyincreation這個set中有沒有包含傳入的beanname,前面沒有地方設置,所以肯定不包含,所以這個方法返回false,后面的流程就不走了。getsingleton這個方法返回的是null。

下面我們看下關注點2.也是一個getsingleton只不過他是真實的創建bean的過程,我們可以看到傳入了一個匿名的objectfactory的對象,他的getobject方法中調用的是createbean這個真正的創建bean的方法。當然我們可以先擱置一下,繼續看我們的getsingleton方法

?
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
public object getsingleton(string beanname, objectfactory<?> singletonfactory) {
  assert.notnull(beanname, "'beanname' must not be null");
  synchronized (this.singletonobjects) {
   object singletonobject = this.singletonobjects.get(beanname);
   if (singletonobject == null) {
    if (this.singletonscurrentlyindestruction) {
     throw new beancreationnotallowedexception(beanname,
       "singleton bean creation not allowed while the singletons of this factory are in destruction " +
       "(do not request a bean from a beanfactory in a destroy method implementation!)");
    }
    if (logger.isdebugenabled()) {
     logger.debug("creating shared instance of singleton bean '" + beanname + "'");
    }
    beforesingletoncreation(beanname);
    boolean newsingleton = false;
    boolean recordsuppressedexceptions = (this.suppressedexceptions == null);
    if (recordsuppressedexceptions) {
     this.suppressedexceptions = new linkedhashset<exception>();
    }
    try {
     singletonobject = singletonfactory.getobject();
     newsingleton = true;
    }
    catch (illegalstateexception ex) {
     // has the singleton object implicitly appeared in the meantime ->
     // if yes, proceed with it since the exception indicates that state.
     singletonobject = this.singletonobjects.get(beanname);
     if (singletonobject == null) {
      throw ex;
     }
    }
    catch (beancreationexception ex) {
     if (recordsuppressedexceptions) {
      for (exception suppressedexception : this.suppressedexceptions) {
       ex.addrelatedcause(suppressedexception);
      }
     }
     throw ex;
    }
    finally {
     if (recordsuppressedexceptions) {
      this.suppressedexceptions = null;
     }
     aftersingletoncreation(beanname);
    }
    if (newsingleton) {
     addsingleton(beanname, singletonobject);
    }
   }
   return (singletonobject != null_object ? singletonobject : null);
  }
 }

這個方法的第一句object singletonobject = this.singletonobjects.get(beanname)從一級緩存中取數據,肯定是null。隨后就調用的beforesingletoncreation方法。

?
1
2
3
4
5
protected void beforesingletoncreation(string beanname) {
  if (!this.increationcheckexclusions.contains(beanname) && !this.singletonscurrentlyincreation.add(beanname)) {
   throw new beancurrentlyincreationexception(beanname);
  }
 }

其中就有往singletonscurrentlyincreation這個set中添加beanname的過程,這個set很重要,后面會用到。隨后就是調用singletonfactory的getobject方法進行真正的創建過程,下面我們看下剛剛上文提到的真正的創建的過程createbean,它里面的核心邏輯是docreatebean.

?
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
protected object docreatebean(final string beanname, final rootbeandefinition mbd, final object[] args) {
  // instantiate the bean.
  beanwrapper instancewrapper = null;
  if (mbd.issingleton()) {
   instancewrapper = this.factorybeaninstancecache.remove(beanname);
  }
  if (instancewrapper == null) {
   instancewrapper = createbeaninstance(beanname, mbd, args);
  }
  final object bean = (instancewrapper != null ? instancewrapper.getwrappedinstance() : null);
  class<?> beantype = (instancewrapper != null ? instancewrapper.getwrappedclass() : null);
 
  // allow post-processors to modify the merged bean definition.
  synchronized (mbd.postprocessinglock) {
   if (!mbd.postprocessed) {
    applymergedbeandefinitionpostprocessors(mbd, beantype, beanname);
    mbd.postprocessed = true;
   }
  }
 
  // eagerly cache singletons to be able to resolve circular references
  // even when triggered by lifecycle interfaces like beanfactoryaware.
  //關注點3
  boolean earlysingletonexposure = (mbd.issingleton() && this.allowcircularreferences &&
    issingletoncurrentlyincreation(beanname));
  if (earlysingletonexposure) {
   if (logger.isdebugenabled()) {
    logger.debug("eagerly caching bean '" + beanname +
      "' to allow for resolving potential circular references");
   }
   addsingletonfactory(beanname, new objectfactory<object>() {
    @override
    public object getobject() throws beansexception {
     return getearlybeanreference(beanname, mbd, bean);
    }
   });
  }
 
  // initialize the bean instance.
  object exposedobject = bean;
  try {
   populatebean(beanname, mbd, instancewrapper);
   if (exposedobject != null) {
    exposedobject = initializebean(beanname, exposedobject, mbd);
   }
  }
  catch (throwable ex) {
   if (ex instanceof beancreationexception && beanname.equals(((beancreationexception) ex).getbeanname())) {
    throw (beancreationexception) ex;
   }
   else {
    throw new beancreationexception(mbd.getresourcedescription(), beanname, "initialization of bean failed", ex);
   }
  }
 
  if (earlysingletonexposure) {
   object earlysingletonreference = getsingleton(beanname, false);
   if (earlysingletonreference != null) {
    if (exposedobject == bean) {
     exposedobject = earlysingletonreference;
    }
    else if (!this.allowrawinjectiondespitewrapping && hasdependentbean(beanname)) {
     string[] dependentbeans = getdependentbeans(beanname);
     set<string> actualdependentbeans = new linkedhashset<string>(dependentbeans.length);
     for (string dependentbean : dependentbeans) {
      if (!removesingletonifcreatedfortypecheckonly(dependentbean)) {
       actualdependentbeans.add(dependentbean);
      }
     }
     if (!actualdependentbeans.isempty()) {
      throw new beancurrentlyincreationexception(beanname,
        "bean with name '" + beanname + "' has been injected into other beans [" +
        stringutils.collectiontocommadelimitedstring(actualdependentbeans) +
        "] in its raw version as part of a circular reference, but has eventually been " +
        "wrapped. this means that said other beans do not use the final version of the " +
        "bean. this is often the result of over-eager type matching - consider using " +
        "'getbeannamesoftype' with the 'alloweagerinit' flag turned off, for example.");
     }
    }
   }
  }
 
  // 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利用反射創建了對象,下面我們看看關注點3 earlysingletonexposure屬性值的判斷,其中有一個判斷點就是issingletoncurrentlyincreation(beanname)

?
1
2
3
public boolean issingletoncurrentlyincreation(string beanname) {
  return this.singletonscurrentlyincreation.contains(beanname);
 }

發現使用的是singletonscurrentlyincreation這個set,上文的步驟中已經將beanname已經填充進去了,所以可以查到,所以earlysingletonexposure這個屬性是結合其他的條件綜合判斷為true,進行下面的流程addsingletonfactory,這里是為這個bean添加objectfactory,這個beanname(a)對應的對象工廠,他的getobject方法的實現是通過getearlybeanreference這個方法實現的。首先我們看下addsingletonfactory的實現

?
1
2
3
4
5
6
7
8
9
10
protected void addsingletonfactory(string beanname, objectfactory<?> singletonfactory) {
  assert.notnull(singletonfactory, "singleton factory must not be null");
  synchronized (this.singletonobjects) {
   if (!this.singletonobjects.containskey(beanname)) {
    this.singletonfactories.put(beanname, singletonfactory);
    this.earlysingletonobjects.remove(beanname);
    this.registeredsingletons.add(beanname);
   }
  }
 }

往第三級緩存singletonfactories存放數據,清除第二級緩存根據beanname的數據。這里有個很重要的點,是往三級緩存里面set了值,這是spring處理循環依賴的核心點。getearlybeanreference這個方法是getobject的實現,可以簡單認為是返回了一個為填充完畢的a的對象實例。設置完三級緩存后,就開始了填充a對象屬性的過程。下面這段描述,沒有源碼提示,只是簡單的介紹一下。

填充a的時候,發現需要b類型的bean,于是繼續調用getbean方法創建,記性的流程和上面a的完全一致,然后到了填充c類型的bean的過程,同樣的調用getbean(c)來執行,同樣到了填充屬性a的時候,調用了getbean(a),我們從這里繼續說,調用了dogetbean中的object sharedinstance = getsingleton(beanname),相同的代碼,但是處理邏輯完全不一樣了。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protected object getsingleton(string beanname, boolean allowearlyreference) {
  object singletonobject = this.singletonobjects.get(beanname);
  if (singletonobject == null && issingletoncurrentlyincreation(beanname)) {
   synchronized (this.singletonobjects) {
    singletonobject = this.earlysingletonobjects.get(beanname);
    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 != null_object ? singletonobject : null);
 }

還是從singletonobjects獲取對象獲取不到,因為a是在singletonscurrentlyincreation這個set中,所以進入了下面的邏輯,從二級緩存earlysingletonobjects中取,還是沒有查到,然后從三級緩存singletonfactories找到對應的對象工廠調用getobject方法獲取未完全填充完畢的a的實例對象,然后刪除三級緩存的數據,填充二級緩存的數據,返回這個對象a。c依賴a的實例填充完畢了,雖然這個a是不完整的。不管怎么樣c式填充完了,就可以將c放到一級緩存singletonobjects同時清理二級和三級緩存的數據。同樣的流程b依賴的c填充好了,b也就填充好了,同理a依賴的b填充好了,a也就填充好了。spring就是通過這種方式來解決循環引用的。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:https://www.jianshu.com/p/16a44c25c9d9

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 日韩视频一 | 日韩精品dvd| 蜜桃一本色道久久综合亚洲精品冫 | 韩国一大片a毛片 | 欧美扩阴视频 | 欧美一级欧美 | 国产va在线观看 | 一区二区三区四区高清视频 | 久久成人黄色 | 中文字幕在线免费播放 | 日日鲁夜夜视频热线播放 | 五月激情久久 | 一级毛片在线看 | 日韩一级电影在线观看 | 在线看免电影网站 | 国产精品成人av片免费看最爱 | 天天操天天操天天操天天操天天操天天操 | 亚洲码无人客一区二区三区 | 被摁着灌浓精囚禁高h1v1 | 久草在线综合 | 亚洲第一页中文字幕 | 91久久另类重口变态 | 第一区免费在线观看 | 久久久久亚洲精品 | 亚洲一区在线免费视频 | 中文字幕一区在线观看视频 | 久久亚洲成人网 | 日日夜av| 欧美1区2区在线观看 | 久久久久久亚洲综合影院红桃 | 在线亚洲综合 | 国产va在线观看 | 欧美一级黄带 | 一区二区免费看 | 久久九九热re6这里有精品 | 国产一区二区三区视频在线观看 | 色婷婷久久一区二区 | 欧美成人高清在线 | 羞羞网站在线看 | 欧美a黄 | 羞羞视频免费入口网站 |