स्प्रिंग कंटेनर में सिंगलटन डिजाइन पैटर्न बनाम सिंगलटन बीन्स


90

जैसा कि हम सभी जानते हैं कि हमारे पास स्प्रिंग कंटेनर में डिफ़ॉल्ट रूप से सिंगलटन के रूप में बीन्स हैं और अगर हमारे पास स्प्रिंग फ्रेमवर्क पर आधारित एक वेब एप्लिकेशन है तो उस स्थिति में क्या हमें वास्तव में बसंत के माध्यम से बीन बनाने के बजाय ग्लोबल डेटा रखने के लिए सिंगलटन डिजाइन पैटर्न को लागू करने की आवश्यकता है ।

कृपया मेरे साथ सहन करें यदि मैं यह समझाने में सक्षम नहीं हूं कि वास्तव में मैं क्या पूछना चाहता था।

जवाबों:


59

स्प्रिंग में एक सिंगलटन बीन और सिंगलटन पैटर्न काफी अलग हैं। सिंगलटन पैटर्न का कहना है कि एक विशेष वर्ग का एक और केवल एक उदाहरण कभी प्रति क्लास लोडर बनाया जाएगा।

स्प्रिंग सिंगलटन के दायरे को "प्रति कंटेनर प्रति बीन" के रूप में वर्णित किया गया है। यह स्प्रिंग IoC कंटेनर प्रति एकल ऑब्जेक्ट उदाहरण के लिए बीन परिभाषा की गुंजाइश है। स्प्रिंग में डिफ़ॉल्ट गुंजाइश सिंगलटन है।

भले ही डिफ़ॉल्ट स्कोप सिंगलटन है, आप <bean ../>तत्व के स्कोप विशेषता को निर्दिष्ट करके बीन के दायरे को बदल सकते हैं ।

<bean id=".." class=".." scope="prototype" />

12
@ user184794: प्रति कंटेनर प्रति बीन, जिसका अर्थ है कि स्प्रिंग कंटेनर में केवल एक ही क्लास लोडर है। यदि स्प्रिंग कंटेनर में दो या दो से अधिक क्लास-लोडर हैं, तो प्रत्येक क्लास-लोडर का अपना उदाहरण होगा। क्या इसका मतलब है "प्रति कंटेनर प्रति क्लासलोडर प्रति बीन"। कृपया स्पष्ट करें !!
डेड प्रोग्रामर

4
मुझे लगता है कि इसका मतलब है कि एक स्प्रिंग कंटेनर एक एकल क्लास लोडर का उपयोग करेगा जो इसका मालिक है। आप वसंत के तंत्र के बाहर क्या करते हैं, यह प्रासंगिक नहीं है, अर्थात आप अपने स्वयं के क्लास लोडर बना सकते हैं और अपनी इच्छानुसार कक्षा के कई उदाहरण बना सकते हैं, लेकिन यदि आप स्प्रिंग कंटेनर से गुजरते हैं, तो यह एक से अधिक उदाहरण नहीं बनाएगा
inor

1
जब आप राज्य करते हैं तो वे "बिल्कुल अलग" नहीं होते हैं। एकमात्र अंतर स्कोप है - स्प्रिंग कंटेनर वर्सेज क्लास लोडर
ज़ैक मैकोम्बर

30

स्प्रिंग में सिंगलटन स्कोप का अर्थ है स्प्रिंग संदर्भ में एकल उदाहरण ..
स्प्रिंग कंटेनर केवल बीन प्राप्त करने के लिए बाद में फिर से कॉल के लिए एक ही उदाहरण देता है।


और वसंत अगर सेम के वर्ग वास्तव में सिंगलटन के रूप में है या नहीं कोडित है, अगर वर्ग सिंगलटन जिसका निर्माता निजी, स्प्रिंग उपयोग BeanUtils.instantiateClass (जावाडोक के रूप में रूप में कोडित है परेशान नहीं करता है यहाँ ) सुलभ और आह्वान करने के लिए निर्माता स्थापित करने के लिए यह।

वैकल्पिक रूप से, हम इस तरह सेम परिभाषा में एक कारखाने-विधि विशेषता का उपयोग कर सकते हैं

    <bean id="exampleBean" class="example.Singleton"  factory-method="getInstance"/>

1
क्या आप सुनिश्चित हैं कि आपको फैक्टरी-विधि विशेषता की आवश्यकता है? मुझे पूरा यकीन है कि वसंत जानता है कि कैसे एक उदाहरण प्राप्त करने के लिए भले ही निर्माता निजी है (शायद कॉल करने की कोशिश करता है GetInstance)
Inor

स्प्रिंग ने निजी निर्माणकर्ता को यहां
ज़ियावेई झांग

21

चलो सबसे सरल उदाहरण लेते हैं: आपके पास एक एप्लिकेशन है और आप बस डिफ़ॉल्ट क्लास लोडर का उपयोग करते हैं। आपके पास एक वर्ग है, जो भी कारण से, आप तय करते हैं कि आवेदन में इसका एक से अधिक उदाहरण नहीं होना चाहिए। (एक परिदृश्य के बारे में सोचो जहां कई लोग आवेदन के टुकड़ों पर काम करते हैं)।

यदि आप स्प्रिंग फ्रेमवर्क का उपयोग नहीं कर रहे हैं, तो सिंगलटन पैटर्न यह सुनिश्चित करता है कि आपके आवेदन में एक वर्ग के एक से अधिक उदाहरण नहीं होंगे। ऐसा इसलिए है क्योंकि आप 'नया' करके वर्ग के उदाहरणों को तुरंत नहीं बना सकते क्योंकि कंस्ट्रक्टर निजी है। कक्षा का एक उदाहरण प्राप्त करने का एकमात्र तरीका कक्षा के कुछ स्थिर तरीके (जिसे आमतौर पर 'getInstance' कहा जाता है) को कॉल करना है, जो हमेशा एक ही उदाहरण देता है।

यह कहते हुए कि आप अपने आवेदन में स्प्रिंग फ्रेमवर्क का उपयोग कर रहे हैं, बस इसका मतलब है कि कक्षा का एक उदाहरण प्राप्त करने के नियमित तरीकों के अलावा (नए या स्थिर तरीके जो कक्षा का एक उदाहरण लौटाते हैं), आप वसंत को भी आपको प्राप्त करने के लिए कह सकते हैं। उस वर्ग और स्प्रिंग का एक उदाहरण यह सुनिश्चित करेगा कि जब भी आप उससे उस कक्षा के उदाहरण के लिए कहेंगे तो वह हमेशा उसी उदाहरण को लौटाएगा, भले ही आपने सिंगलटन पैटर्न का उपयोग करके कक्षा क्यों न लिखी हो। दूसरे शब्दों में, भले ही वर्ग में एक सार्वजनिक निर्माणकर्ता हो, यदि आप हमेशा वसंत को उस वर्ग के उदाहरण के लिए पूछते हैं, तो वसंत केवल उस निर्माता को आपके आवेदन के जीवन के दौरान एक बार कॉल करेगा।

आम तौर पर यदि आप स्प्रिंग का उपयोग कर रहे हैं, तो आपको केवल इंस्टेंस बनाने के लिए स्प्रिंग का उपयोग करना चाहिए, और आपके पास क्लास के लिए एक सार्वजनिक कंस्ट्रक्टर हो सकता है। लेकिन अगर आपका कंस्ट्रक्टर निजी नहीं है, तो आप किसी को भी स्प्रिंग को दरकिनार करते हुए सीधे वर्ग के नए उदाहरण बनाने से नहीं रोक सकते।

यदि आप वास्तव में वर्ग का एक भी उदाहरण चाहते हैं, भले ही आप अपने आवेदन में स्प्रिंग का उपयोग करें और एक सिंगलटन होने के लिए स्प्रिंग में क्लास को परिभाषित करें, यह सुनिश्चित करने का एकमात्र तरीका है कि सिंगलटन पैटर्न का उपयोग करके भी क्लास को लागू करें। यह सुनिश्चित करता है कि एक एकल उदाहरण होगा, चाहे लोग वसंत का उपयोग एक उदाहरण प्राप्त करने के लिए करें या वसंत को बायपास करें।


13

मुझे लगता है कि " प्रति कंटेनर प्रति बीन" मुश्किल है । मैं कहूंगा " एक कंटेनर में एक बीन आईडी प्रति सेम "। इसे समझने के लिए एक उदाहरण है। हमारे पास बीन क्लास नमूना है। मैंने इस वर्ग से सेम की परिभाषा में दो फलियों को परिभाषित किया है, जैसे:

<bean id="id1" class="com.example.Sample" scope="singleton">
        <property name="name" value="James Bond 001"/>    
</bean>    
<bean id="id7" class="com.example.Sample" scope="singleton">
        <property name="name" value="James Bond 007"/>    
</bean>

इसलिए जब भी मैं बीन को आईडी "आईडी 1" के साथ प्राप्त करने की कोशिश करता हूं, तो वसंत कंटेनर एक बीन बनाएगा, इसे कैश करेगा और उसी बीन को वापस करेगा जहां कभी भी आईडी 1 के साथ संदर्भित किया जाता है। अगर मैं इसे id7 के साथ प्राप्त करने का प्रयास करता हूं, तो नमूना वर्ग से एक और बीन बनाई जाएगी, उसी को कैश किया जाएगा और प्रत्येक बार जब आपने id7 के साथ संदर्भित किया था तो वापस कर दिया जाएगा।

यह सिंगलटन पैटर्न के साथ संभावना नहीं है। सिंग्लटन पैटर्न में प्रति वर्ग लोडर एक वस्तु हमेशा बनाई जाती है। हालांकि स्प्रिंग में, सिंग्लटन के रूप में गुंजाइश बनाने से कंटेनर को उस वर्ग से कई उदाहरण बनाने से प्रतिबंधित नहीं किया जाता है। यह सिर्फ उसी आईडी के लिए नए ऑब्जेक्ट निर्माण को फिर से प्रतिबंधित करता है, पहले से बनाई गई वस्तु को वापस करते हुए जब उसी आईडी के लिए ऑब्जेक्ट का अनुरोध किया जाता हैसंदर्भ


अच्छी तरह समझाया। धन्यवाद!
स्वप्निल

12

स्प्रिंग में सिंगलटन स्कोप का अर्थ है कि यह बीन केवल स्प्रिंग द्वारा एक बार ही इंस्टेंट किया जाएगा। प्रोटोटाइप स्कोप (हर बार नया उदाहरण) के विपरीत, अनुरोध स्कोप (एक बार अनुरोध के अनुसार), सत्र स्कोप (एक बार HTTP सत्र)

सिंग्लटन स्कोप का तकनीकी रूप से सिंगलटन डिज़ाइन पैटर्न से कोई लेना-देना नहीं है। आपको अपने बीन्स को सिंगलटन के रूप में कार्यान्वित करने की आवश्यकता नहीं है क्योंकि उन्हें सिंगलटन दायरे में रखा जाना चाहिए।


1
मुझे सही करें अगर मैं आपके अनुसार गलत हूं तो मुझे किसी भी ऑब्जेक्ट को सिंगलटन के रूप में लागू करने की आवश्यकता है, इसलिए सिंगलटन पैटर्न को लागू करने की कोई आवश्यकता नहीं है। स्प्रिंग का उपयोग करके उस बीन को बनाना काम करेगा। स्प्रिंग फ्रेमवर्क में सिंगलटन डिज़ाइन पैटर्न और सिंगलटन स्कोप से संबंधित मेरी समझ से अब मैं थोड़ा भ्रमित हूँ।
पीयूष

1
स्प्रिंग आपको सिंगलटन पैटर्न का उपयोग करने के लिए मजबूर नहीं करता है।
lexicore

2

स्प्रिंग में सिंगलटन बीन्स और सिंग्लटन डिजाइन पैटर्न पर आधारित कक्षाएं काफी अलग हैं।

सिंगलटन पैटर्न यह सुनिश्चित करता है कि किसी विशेष वर्ग का एक और केवल एक उदाहरण प्रति कक्षा लोडर बनाया जाएगा जहां स्प्रिंग सिंगलटन बीन के दायरे को 'प्रति कंटेनर प्रति बीन' के रूप में वर्णित किया गया है। स्प्रिंग में सिंगलटन स्कोप का अर्थ है कि यह बीन केवल स्प्रिंग द्वारा एक बार ही इंस्टेंट किया जाएगा। स्प्रिंग कंटेनर केवल बीन प्राप्त करने के लिए बाद में फिर से कॉल के लिए एक ही उदाहरण देता है।


13
आप 'जावा मवरिक' हैं, है ना? यह आपका कथन, "एक अच्छी व्याख्या और उदाहरण मिला ..." को छिपाने के लिए एक बेईमान प्रयास है जिसे आप अपनी वेबसाइट से जोड़ रहे हैं। आपका लिंक वैसे भी उत्तर के लिए महत्वपूर्ण नहीं लगता है। मैं इसे हटा रहा हूं, ताकि स्पैम के रूप में हटाए जा रहे उत्तर से बचा जा सके। अपनी वेबसाइट पर किसी भी लिंक को पोस्ट करने से पहले सेल्फ-प्रमोशन पर अक्सर पूछे जाने वाले प्रश्न पढ़ें। यह भी ध्यान दें कि अपनी प्रोफ़ाइल में अपनी वेबसाइट लिंक डालना आपके लिए काफी ठीक है।
एंड्रयू नाई

2

दोनों के बीच बहुत बुनियादी अंतर है। सिंग्लटन डिज़ाइन पैटर्न के मामले में, प्रति क्लासऑलडर के केवल एक उदाहरण का निर्माण किया जाएगा, जबकि स्प्रिंग सिंगलटन के साथ ऐसा नहीं है, क्योंकि दिए गए आईडी प्रति IoC कंटेनर के लिए बाद में एक साझा बीन उदाहरण बनाया गया है।

उदाहरण के लिए, यदि मेरे पास "स्प्रिंगटेस्ट" नाम से एक वर्ग है और मेरी XML फ़ाइल कुछ इस तरह दिखती है: -

<bean id="test1" class="com.SpringTest" scope="singleton">
        --some properties here
</bean>    
<bean id="test2" class="com.SpringTest" scope="singleton">
        --some properties here   
</bean>

तो अब मुख्य वर्ग में यदि आप उपरोक्त दोनों के संदर्भ की जाँच करेंगे तो यह स्प्रिंग डॉक्यूमेंटेशन के अनुसार गलत होगा: -

जब एक बीन एक सिंगलटन होता है, तो बीन का केवल एक साझा उदाहरण प्रबंधित किया जाएगा, और सेम या आईडी के साथ सेम के लिए सभी अनुरोधों का मिलान उस बीन परिभाषा के परिणामस्वरूप होगा कि एक विशिष्ट बीन का उदाहरण स्प्रिंग कंटेनर द्वारा वापस किया जा रहा है

इसलिए जैसा कि हमारे मामले में, कक्षाएं समान हैं लेकिन हमने जो आईडी प्रदान की है वह अलग है इसलिए परिणामस्वरूप दो अलग-अलग उदाहरण बनाए जा रहे हैं।


1

वसंत में "सिंगलटन" बीन फैक्टरी का उपयोग कर रहा है उदाहरण प्राप्त करें, फिर इसे कैश करें; जो सिंगलटन डिजाइन पैटर्न कड़ाई से है, उदाहरण केवल स्थैतिक प्राप्त विधि से प्राप्त किया जा सकता है, और वस्तु को कभी भी सार्वजनिक रूप से त्वरित नहीं किया जा सकता है।


1

EX: "प्रति कंटेनर प्रति बीन"।

        <bean id="myBean" class="com.spring4hibernate4.TestBean">
            <constructor-arg name="i" value="1"></constructor-arg>
            <property name="name" value="1-name"></property>
        </bean>

        <bean id="testBean" class="com.spring4hibernate4.TestBean">
            <constructor-arg name="i" value="10"></constructor-arg>
            <property name="name" value="10-name"></property>
        </bean>
    </beans>



    public class Test {

        @SuppressWarnings("resource")
        public static void main(String[] args) {
            ApplicationContext ac = new ClassPathXmlApplicationContext("ws.xml");
            TestBean teatBean = (TestBean) ac.getBean("testBean");
            TestBean myBean1 = (TestBean) ac.getBean("myBean");
            System.out.println("a : " + teatBean.test + " : "   + teatBean.getName());
            teatBean.setName("a TEST BEAN 1");
            System.out.println("uPdate : " + teatBean.test + " : "  + teatBean.getName());
            System.out.println("a1 : " + myBean1.test + " : " + myBean1.getName());
            myBean1.setName(" a1 TEST BEAN 10");
            System.out.println("a1 update : " + teatBean.test + " : " + myBean1.getName());
        }
    }

public class TestBean {
    public int test = 0;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private String name = "default";

    public TestBean(int i) {
        test += i;
    }
}

जावा सिंहटन:

public class Singleton {
    private static Singleton singleton = new Singleton();
    private int i = 0;

    private Singleton() {
    }

    public static Singleton returnSingleton() {

        return singleton;
    }

    public void increment() {
        i++;
    }

    public int getInt() {
        return i;
    }
}

public static void main(String[] args) {
        System.out.println("Test");

        Singleton sin1 = Singleton.returnSingleton();
        sin1.increment();
        System.out.println(sin1.getInt());
        Singleton sin2 = Singleton.returnSingleton();
        System.out.println("Test");
        sin1.increment();
        System.out.println(sin1.getInt());
    }

<bean class = "com.spring4hibernate4.TestBean"> <constructor-arg name = "i" value = "1"> </ constructor-arg> <संपत्ति का नाम = "नाम" मान = "1-नाम"> </ प्रॉपर्टी> </ b>> बीन क्लास = "com.spring4hibernate4.TestBean"> <कंस्ट्रक्टर-arg name = "i" value = "10"> </ constructor-arg> <b name = "name" value = "10" -नाम "> </ संपत्ति> </ सेम> </ सेम>
हरिप्रसाद

1

स्प्रिंग सिंगलटन बीन को 'प्रति कंटेनर प्रति बीन' कहा जाता है। स्प्रिंग में सिंगलटन स्कोप का मतलब है कि एक ही मेमोरी लोकेशन पर एक ही ऑब्जेक्ट एक ही बीन आईडी पर वापस आ जाएगा। यदि कोई एक ही वर्ग के विभिन्न आईडी के कई बीन्स बनाता है तो कंटेनर विभिन्न वस्तुओं को अलग-अलग आईडी में लौटा देगा। यह एक प्रमुख मूल्य मानचित्रण की तरह है जहां कुंजी बीन आईडी है और मूल्य एक स्प्रिंग कंटेनर में बीन ऑब्जेक्ट है। जहां सिंग्लटन पैटर्न यह सुनिश्चित करता है कि किसी विशेष वर्ग का एक और केवल एक उदाहरण प्रति क्लास लोडर बनाया जाएगा।


1

सभी उत्तर, अब तक कम से कम, डिज़ाइन पैटर्न और स्प्रिंग सिंगलटन के बीच अंतर को समझाने पर ध्यान केंद्रित करते हैं और आपके वास्तविक प्रश्न को संबोधित नहीं करते हैं: क्या सिंगलटन डिज़ाइन पैटर्न का उपयोग किया जाना चाहिए या स्प्रिंग सिंगलटन सेम? क्या बेहतर है?

इससे पहले कि मैं जवाब दूं कि आप मुझे बताएं कि आप दोनों क्या कर सकते हैं। आप सेम को सिंगलटन डिज़ाइन पैटर्न के रूप में लागू कर सकते हैं और स्प्रिंग को सिंगल सिंगलटन बीन के रूप में ग्राहक वर्गों में इंजेक्ट करने के लिए उपयोग कर सकते हैं।

अब, प्रश्न का उत्तर सरल है: सिंगलटन डिज़ाइन पैटर्न का उपयोग न करें!
सार्वजनिक निर्माणकर्ता के साथ एक वर्ग के रूप में लागू स्प्रिंग के सिंगलटन बीन का उपयोग करें।
क्यों? क्योंकि सिंगलटन डिज़ाइन पैटर्न को एक एंटी-पैटर्न माना जाता है। ज्यादातर क्योंकि यह परीक्षण को जटिल बनाता है। (और यदि आप इसे इंजेक्ट करने के लिए स्प्रिंग का उपयोग नहीं करते हैं, तो सिंगलटन का उपयोग करने वाले सभी वर्ग अब इसे कसकर बाध्य कर रहे हैं), और आप इसे प्रतिस्थापित या विस्तारित नहीं कर सकते। इस बारे में अधिक जानकारी प्राप्त करने के लिए "सिंग्लटन एंटी-पैटर्न" को गूगल कर सकता है, जैसे कि सिंगलटन एंटी-पैटर्न

स्प्रिंग सिंगलटन का उपयोग करने का तरीका है (एक सिंगलटन बीन के साथ लागू किया गया जो सिंगलटन डिजाइन पैटर्न के रूप में लागू नहीं है, बल्कि एक सार्वजनिक निर्माणकर्ता के साथ) ताकि स्प्रिंग सिंगलटन बीन का आसानी से परीक्षण किया जा सके और इसका उपयोग करने वाली कक्षाओं को कसकर युग्मित नहीं किया जा सके। , लेकिन इसके बजाय, स्प्रिंग ने सिंगलटन को एक इंटरफेस के रूप में इंजेक्ट किया, जो सभी बीन्स को इसकी आवश्यकता होती है, और सिंगलटन बीन को किसी भी समय किसी अन्य कार्यान्वयन के साथ बदल दिया जा सकता है बिना उपयोग किए क्लाइंट क्लासेस को प्रभावित किए।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.