वसंत इसे कैसे हल करता है: बीन ए बीन बी पर निर्भर है, और बीन बी सेम ए पर निर्भर है।
वसंत इसे कैसे हल करता है: बीन ए बीन बी पर निर्भर है, और बीन बी सेम ए पर निर्भर है।
जवाबों:
जैसा कि अन्य जवाबों में कहा गया है, स्प्रिंग बस इसका ध्यान रखती है, फलियों को बनाना और उन्हें आवश्यकतानुसार इंजेक्ट करना।
परिणामों में से एक यह है कि बीन इंजेक्शन / प्रॉपर्टी सेटिंग एक अलग क्रम में हो सकती है कि आपकी XML वायरिंग फ़ाइलों का क्या मतलब होगा। इसलिए आपको सावधान रहने की जरूरत है कि आपकी संपत्ति बसने वाले शुरुआती काम पर निर्भर नहीं करती है जो पहले से ही कहे जा रहे अन्य बाशिंदों पर निर्भर है। इससे निपटने का तरीका InitializingBean
इंटरफ़ेस को लागू करने के रूप में बीन्स की घोषणा करना है। इसके लिए आपको afterPropertiesSet()
विधि को लागू करने की आवश्यकता है , और यह वह जगह है जहाँ आप महत्वपूर्ण आरंभीकरण करते हैं। (मैं यह जांचने के लिए कोड भी शामिल करता हूं कि महत्वपूर्ण गुण वास्तव में सेट किए गए हैं।)
वसंत संदर्भ मैनुअल बताते हैं कि कैसे परिपत्र निर्भरता हल कर रहे हैं। फलियों को पहले से सूंघा जाता है, फिर एक दूसरे में इंजेक्ट किया जाता है।
इस वर्ग पर विचार करें:
package mypackage;
public class A {
public A() {
System.out.println("Creating instance of A");
}
private B b;
public void setB(B b) {
System.out.println("Setting property b of A instance");
this.b = b;
}
}
और एक समान श्रेणी B
:
package mypackage;
public class B {
public B() {
System.out.println("Creating instance of B");
}
private A a;
public void setA(A a) {
System.out.println("Setting property a of B instance");
this.a = a;
}
}
यदि आपके पास यह कॉन्फ़िगरेशन फ़ाइल थी:
<bean id="a" class="mypackage.A">
<property name="b" ref="b" />
</bean>
<bean id="b" class="mypackage.B">
<property name="a" ref="a" />
</bean>
इस कॉन्फ़िगरेशन का उपयोग करते हुए संदर्भ बनाते समय आपको निम्न आउटपुट दिखाई देंगे:
Creating instance of A
Creating instance of B
Setting property a of B instance
Setting property b of A instance
ध्यान दें कि कब a
इंजेक्ट किया जाता है b
, a
अभी तक पूरी तरह से आरंभिक नहीं है।
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
कोडबेस में मैं (1 मिलियन + लाइनों की कोड) के साथ काम कर रहा हूं, हमें लंबे स्टार्टअप समय, लगभग 60 सेकंड के साथ समस्या थी। हमें 12000+ FactoryBeanNotInitializedException मिल रही थी ।
मैंने जो किया था वह AbstractBeanFactory # doGetBean में एक सशर्त विराम बिंदु निर्धारित किया गया था
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;
}
यह कहाँ है destroySingleton(beanName)
मैंने सशर्त ब्रेकपॉइंट कोड के साथ अपवाद मुद्रित किया है:
System.out.println(ex);
return false;
स्पष्ट रूप से ऐसा तब होता है जब FactoryBean s चक्रीय निर्भरता ग्राफ में शामिल होता है । हमने ApplicationContextAware और InitializingBean को लागू करके और सेम को मैन्युअल रूप से इंजेक्ट करके इसे हल किया ।
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class A implements ApplicationContextAware, InitializingBean{
private B cyclicDepenency;
private ApplicationContext ctx;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
ctx = applicationContext;
}
@Override
public void afterPropertiesSet() throws Exception {
cyclicDepenency = ctx.getBean(B.class);
}
public void useCyclicDependency()
{
cyclicDepenency.doSomething();
}
}
इसने स्टार्टअप समय को लगभग 15 सेकंड तक घटा दिया।
इसलिए हमेशा यह न समझें कि वसंत आपके लिए इन संदर्भों को हल करने में अच्छा हो सकता है।
इस कारण से मैं कई भविष्य की समस्याओं को रोकने के लिए AbstractRefreshableApplicationContext # setAllowCircularReferences (झूठा) के साथ चक्रीय निर्भरता संकल्प को अक्षम करने की सिफारिश करूंगा ।
समस्या ->
Class A {
private final B b; // must initialize in ctor/instance block
public A(B b) { this.b = b };
}
Class B {
private final A a; // must initialize in ctor/instance block
public B(A a) { this.a = a };
}
// इसके कारण: org.springframework.beans.factory.BeanCurrentlyInCreationException: नाम 'ए' के साथ बीन बनाने में त्रुटि: अनुरोधित बीन वर्तमान में निर्माण में है: क्या एक अनपेक्षित परिपत्र संदर्भ है?
समाधान 1 ->
Class A {
private B b;
public A( ) { };
//getter-setter for B b
}
Class B {
private A a;
public B( ) { };
//getter-setter for A a
}
समाधान 2 ->
Class A {
private final B b; // must initialize in ctor/instance block
public A(@Lazy B b) { this.b = b };
}
Class B {
private final A a; // must initialize in ctor/instance block
public B(A a) { this.a = a };
}
यह बस करता है। यह त्वरित a
औरb
, और प्रत्येक को एक दूसरे में इंजेक्ट करता है (उनके सेटर विधियों का उपयोग करके)।
समस्या क्या है?
से वसंत संदर्भ :
आप आम तौर पर सही काम करने के लिए वसंत पर भरोसा कर सकते हैं। यह कंटेनर लोड-टाइम पर गैर-मौजूद बीन्स और परिपत्र निर्भरता के संदर्भ जैसे कॉन्फ़िगरेशन समस्याओं का पता लगाता है। वसंत गुण निर्धारित करता है और निर्भरता को यथासंभव देर से हल करता है, जब बीन वास्तव में बनाई जाती है।
स्प्रिंग कंटेनर सेटर-आधारित परिपत्र निर्भरता को हल करने में सक्षम है, लेकिन कंस्ट्रक्टर-आधारित परिपत्र निर्भरता के मामले में एक रनटाइम अपवाद BeanCurrentlyInCreationException देता है। सेटर-आधारित परिपत्र निर्भरता के मामले में, आईओसी कंटेनर इसे एक विशिष्ट परिदृश्य से अलग तरीके से संभालता है, जिसमें यह इंजेक्शन लगाने से पहले सहयोगी सेम को पूरी तरह से कॉन्फ़िगर करेगा। उदाहरण के लिए, यदि बीन ए पर बीन बी और बीन बी पर निर्भरता है, तो कंटेनर बी को इंजेक्ट करने से पहले पूरी तरह से सी को इनिशियलाइज़ करता है और एक बार बी को पूरी तरह से इनिशियलाइज़ करने के बाद इसे ए पर इंजेक्ट कर दिया जाता है, लेकिन परिपत्र निर्भरता के मामले में, एक पूरी तरह से शुरू होने से पहले फलियों को दूसरे में इंजेक्ट किया जाता है।
कहते हैं कि A, B पर निर्भर करता है, तो वसंत पहले A, फिर B से बी लेगा, फिर B के लिए गुण सेट करेगा, फिर B को A में सेट करेगा।
लेकिन क्या होगा अगर बी भी ए पर निर्भर करता है?
मेरी समझ यह है: वसंत ने पाया कि ए का निर्माण किया गया है (कंस्ट्रक्टर निष्पादित), लेकिन पूरी तरह से आरंभीकृत नहीं (नहीं किए गए सभी इंजेक्शन), ठीक है, यह सोचा, यह ठीक है, यह सहन करने योग्य है कि ए पूरी तरह से आरंभीकृत नहीं है, बस इसे सेट करें- अभी के लिए बी में पूरी तरह से प्रारंभिक ए उदाहरण। बी पूरी तरह से शुरू होने के बाद, इसे ए में सेट किया गया था, और आखिरकार, ए को अब पूरी तरह से शुरू किया गया था।
दूसरे शब्दों में, यह पहले से ए से बी को उजागर करता है।
कंस्ट्रक्टर के माध्यम से निर्भरता के लिए, स्प्रिंट सिर्फ बीनक्रिकेटलीइन्क्रिएशन एक्ससेप्शन को फेंक देते हैं, इस अपवाद को हल करने के लिए, बीन के लिए आलसी-इनिट सेट करें जो कंस्ट्रक्टर-आरजी मार्ग के माध्यम से दूसरों पर निर्भर करता है।
इसकी स्पष्ट व्याख्या यहां दी गई है । युगेन पारशिव को धन्यवाद।
परिपत्र निर्भरता एक डिजाइन गंध है, या तो इसे ठीक करें या निर्भरता के लिए @Lazy का उपयोग करें जो इसे हल करने के लिए समस्या का कारण बनता है।
यदि आप आम तौर पर कंस्ट्रक्टर-इंजेक्शन का उपयोग करते हैं और संपत्ति-इंजेक्शन पर स्विच नहीं करना चाहते हैं, तो स्प्रिंग का लुकअप-मेथड- इनजेक्शन एक बीन को आलसी रूप से दूसरे को देखने देगा और इसलिए चक्रीय निर्भरता को हल कर देगा। यहां देखें: http://docs.spring.io/spring/docs/1.2.9/reference/beans.html#d0e1161
वसंत फलियों के बीच सर्कुलर डिपेंडेंसी होने पर कंस्ट्रक्टर इंजेक्शन फेल हो जाता है। तो इस मामले में हम सेटर इंजेक्शन समस्या को हल करने में मदद करते हैं।
मूल रूप से, कंस्ट्रक्टर इंजेक्शन अनिवार्य निर्भरता के लिए, सेटर इंजेक्शन का उपयोग करने के लिए बेहतर है, क्योंकि हम फिर से इंजेक्शन कर सकते हैं।
यदि दो फलियाँ एक दूसरे पर निर्भर हैं तो हमें बीन की दोनों परिभाषाओं में कंस्ट्रक्टर इंजेक्शन का उपयोग नहीं करना चाहिए। इसके बजाय हमें सेम में से किसी एक में सेटर इंजेक्शन का उपयोग करना होगा। (बेशक हम दोनों सेम परिभाषाओं में सेटर इंजेक्शन एन का उपयोग कर सकते हैं, लेकिन दोनों 'बीनक्रिकेटलीइन्क्रिएशन एक्ससेप्शन' में कंस्ट्रक्टर इंजेक्शन फेंक देते हैं।
वसंत डॉक को " https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#resource-resource " पर देखें