Singleton tasarım deseni vs Spring konteynerde Singleton çekirdekler


90

Hepimizin bildiği gibi, bahar kapsayıcısında varsayılan olarak tekli fasulyelerimiz var ve eğer Bahar çerçevesine dayalı bir web uygulamamız varsa, o zaman bu durumda, sadece ilkbaharda bir fasulye oluşturmak yerine, küresel verileri tutmak için gerçekten Singleton tasarım modelini uygulamalı mıyız? .

Gerçekte ne sormak istediğimi açıklayamazsam lütfen bana katlanın.

Yanıtlar:


61

İlkbaharda bir tekli fasulye ve tekli desen oldukça farklı. Singleton kalıbı, sınıf yükleyici başına belirli bir sınıfın yalnızca bir örneğinin oluşturulacağını söyler.

Bir Bahar tekliğinin kapsamı, "çekirdek başına kap başına" olarak tanımlanır. Her Spring IoC konteyneri için tek bir nesne örneğine fasulye tanımının kapsamıdır. Spring'deki varsayılan kapsam Singleton'dur.

Varsayılan kapsam tekil olsa bile, <bean ../>öğenin kapsam özniteliğini belirterek bean kapsamını değiştirebilirsiniz .

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

12
@ user184794: fasulye başına konteyner başına, yani yay konteynerinde yalnızca bir sınıf yükleyici vardır. yay konteynerinde iki veya daha fazla sınıf yükleyici varsa, o zaman her sınıf yükleyicinin kendi örneği olacaktır. "Çekirdek başına sınıf yükleyici başına kap" anlamına mı geliyor? lütfen açıklığa kavuşturun !!
Ölü Programcı

4
Sanırım bu, bir Spring konteynerin sahip olduğu tek bir sınıf yükleyiciyi kullanacağı anlamına geliyor. Ne Bahar mekanizması dışında yani kendi classloaders oluşturabilir ve istediğiniz gibi bir sınıfın Birçok örnekte olduğu gibi yaratmak, ancak Bahar konteyner geçmesi durumunda, bu birden fazla örneği oluşturmaz olabilir, alakalı değil
inor

1
O zaman belirttiğiniz gibi "tamamen farklı" değiller. Tek fark kapsam - Spring container verses classloader
Zack Macomber

31

İlkbaharda tekli kapsam, bir Yay bağlamında tek bir durum anlamına gelir.
Yaylı kap, fasulyeyi almak için sonraki çağrılar için aynı örneği tekrar tekrar döndürür.


Ve spring, fasulye sınıfının singleton olarak kodlanıp kodlanmaması sorununu çözmez, aslında sınıf, yapıcısı özel olan singleton olarak kodlanmışsa, Spring yapıcıyı erişilebilir ve çağırmak için BeanUtils.instantiateClass'ı ( burada javadoc ) kullanın o.

Alternatif olarak, fasulye tanımında bunun gibi bir fabrika yöntemi özniteliği kullanabiliriz

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

1
fabrika yöntemi özelliğine ihtiyacınız olduğundan emin misiniz? Yapıcı özel olsa bile (muhtemelen getInstance'ı çağırmayı dener) Spring'in nasıl örnek alınacağını bildiğinden oldukça eminim
inor

Spring'in burada
Xiawei Zhang

22

En basit örneği ele alalım: bir uygulamanız var ve sadece varsayılan sınıf yükleyiciyi kullanıyorsunuz. Hangi nedenle olursa olsun, uygulamada birden fazla örneği olmamasına karar verdiğiniz bir sınıfınız var. (Birkaç kişinin uygulamanın parçaları üzerinde çalıştığı bir senaryo düşünün).

Spring çerçevesini kullanmıyorsanız, Singleton kalıbı, uygulamanızda bir sınıfın birden fazla örneğinin olmamasını sağlar. Bunun nedeni, yapıcı özel olduğu için 'yeni' yaparak sınıfın örneklerini başlatamazsınız. Sınıfın bir örneğini almanın tek yolu, her zaman aynı örneği döndüren sınıfın bazı statik yöntemlerini (genellikle 'getInstance' olarak adlandırılır) çağırmaktır.

Uygulamanızda Spring çerçevesini kullandığınızı söylemek, sınıfın bir örneğini elde etmenin normal yollarına (sınıfın bir örneğini döndüren yeni veya statik yöntemler) ek olarak, Spring'den sizi almasını isteyebileceğiniz anlamına gelir. Bu sınıfın bir örneği ve Spring, sınıfı Singleton desenini kullanarak yazmamış olsanız bile, ondan o sınıfın bir örneğini sorduğunuzda her zaman aynı örneği döndürmesini sağlayacaktır. Diğer bir deyişle, sınıfın genel kurucusu olsa bile, Spring'den her zaman o sınıfın bir örneğini sorarsanız, Spring bu kurucuyu başvurunuzun ömrü boyunca yalnızca bir kez arayacaktır.

Normalde Spring kullanıyorsanız, örnekler oluşturmak için yalnızca Spring'i kullanmalısınız ve sınıf için genel bir kurucunuz olabilir. Ancak kurucunuz özel değilse, Spring'i atlayarak kimsenin doğrudan sınıfın yeni örneklerini oluşturmasını gerçekten engellemiyorsunuzdur.

Sınıfın gerçekten tek bir örneğini istiyorsanız, uygulamanızda Spring'i kullansanız ve Spring'deki sınıfı bir singleton olarak tanımlasanız bile, bunu sağlamanın tek yolu, sınıfı Singleton modelini kullanarak uygulamaktır. Bu, insanlar bir örnek almak için Spring'i kullansın veya Spring'i baypas etsinler, tek bir örnek olmasını sağlar.


13

" Çekirdek başına kap başına" kavramını anlamakta zorlanıyorum . " Bir kapta çekirdek başına bir çekirdek " diyebilirim. Bunu anlamak için bir örnek verelim. Bean sınıfımız var. Fasulye tanımında bu sınıftaki iki fasulyeyi şöyle tanımladım:

<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>

Bu yüzden, "id1" kimliğine sahip fasulyeyi almaya çalıştığımda, yaylı hazne bir tane oluşturacak, onu önbelleğe alacak ve id1 ile başvurulan her yerde aynı fasulyeyi döndürecektir. İd7 ile almaya çalışırsam, Sample sınıfından başka bir fasulye yaratılacak, aynısı önbelleğe alınacak ve id7 ile her başvurduğunuzda geri gönderilecektir.

Singleton modelinde bu pek olası değildir. Singlton modelinde her zaman sınıf yükleyici başına bir nesne oluşturulur. Ancak İlkbaharda, kapsamı Singleton olarak yapmak, kapsayıcının bu sınıftan birçok örnek oluşturmasını kısıtlamaz. Aynı kimlik için yeni nesne oluşturmayı tekrar kısıtlar ve aynı kimlik için bir nesne talep edildiğinde önceden oluşturulmuş nesneyi döndürür . Referans


İyi açıklanmış. Teşekkürler!
Swapnil

12

Bahardaki Singleton kapsamı, bu fasulyenin Bahar tarafından yalnızca bir kez örnekleneceği anlamına gelir. Prototip kapsamının aksine (her seferinde yeni örnek), istek kapsamı (istek başına bir kez), oturum kapsamı (HTTP oturumu başına bir kez).

Singleton kapsamının teknik olarak singleton tasarım modeliyle hiçbir ilgisi yoktur. Çekirdeklerinizi singleton kapsamına alabilmeniz için tekli olarak uygulamanız gerekmez.


1
Yanlışsam düzeltin, size göre herhangi bir nesneyi tekli olarak uygulamam gerekirse, böylece tekli desen uygulamaya gerek kalmaz. O fasulyeyi Spring kullanarak yaratmak işe yarayacak. Spring çerçevesindeki Singleton Design modeli ve Singleton kapsamı ile ilgili anlayışımla biraz kafam karıştı.
Peeyush

1
Yay sizi Singleton modelini kullanmaya zorlamaz.
lexicore

2

Spring'deki Singleton fasulyeleri ve Singleton tasarım desenine dayalı sınıflar oldukça farklıdır.

Singleton kalıbı, her bir sınıf yükleyici için belirli bir sınıfın yalnızca bir örneğinin oluşturulmasını sağlar; burada Spring singleton bean kapsamı "çekirdek başına kap başına" olarak tanımlanır. Bahardaki Singleton kapsamı, bu fasulyenin Bahar tarafından yalnızca bir kez örnekleneceği anlamına gelir. Yaylı kap, fasulyeyi almak için sonraki çağrılar için aynı örneği tekrar tekrar döndürür.


13
Sen 'java maverick'sin, değil mi? Bu, kendi web sitenize bağlantı verdiğinizi gizlemek için "... adresinde iyi bir açıklama ve örnek buldum" ifadenizi dürüst olmayan bir girişim haline getirir. Bağlantınız yanıt için önemli görünmüyor zaten. Cevabın spam olarak silinmesini önlemek için onu kaldırıyorum. Lütfen web sitenize daha fazla bağlantı göndermeden önce Kişisel Tanıtım ile ilgili SSS bölümünü okuyun. Ayrıca, web sitenizin bağlantısını profilinize koymanızın oldukça iyi olduğunu unutmayın.
Andrew Barber

2

İkisi arasında çok temel bir fark var. Singleton tasarım örüntüsü durumunda, sınıf Yükleyicisi başına yalnızca bir sınıf örneği oluşturulurken, her IoC kabı başına verilen kimlik için daha sonraki bir paylaşılan fasulye örneğinde olduğu gibi Spring singleton'da durum böyle değildir.

Örneğin, "SpringTest" adında bir sınıfım varsa ve XML dosyam şuna benzer: -

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

Yani şimdi ana sınıfta, yukarıdaki ikisinin referansını kontrol ederseniz, Bahar belgelerine göre yanlış döndürür: -

Bir fasulye singleton olduğunda, çekirdeğin yalnızca bir paylaşılan örneği yönetilir ve bu fasulye tanımıyla eşleşen bir kimliği veya kimlikleri olan tüm fasulye istekleri, Bahar kapsayıcısı tarafından belirli bir fasulye örneğinin döndürülmesiyle sonuçlanır.

Bizim durumumuzda olduğu gibi, sınıflar aynıdır, ancak sağladığımız id'ler farklıdır, dolayısıyla iki farklı örnek oluşturulmaktadır.


2

Şimdiye kadarki tüm cevaplar, en azından, tasarım deseni ile Spring singleton arasındaki farkı açıklamaya odaklanıyor ve asıl sorunuzu yanıtlamıyor: Bir Singleton tasarım deseni mi yoksa bir Spring singleton fasulye mi kullanılmalı? ne daha iyi?

Cevap vermeden önce ikisini birden yapabileceğinizi belirtmeme izin verin. Fasulyeyi bir Singleton tasarım deseni olarak uygulayabilir ve Spring'i istemci sınıflarına bir Spring singleton fasulye olarak enjekte etmek için kullanabilirsiniz.

Şimdi sorunun cevabı basit: Singleton tasarım modelini kullanmayın!
Public constructor ile sınıf olarak uygulanan Spring'in singleton bean'ını kullanın.
Neden? Çünkü Singleton tasarım deseni bir anti-desen olarak kabul edilir. Çoğunlukla testi zorlaştırdığı için. (Ve onu enjekte etmek için Spring'i kullanmazsanız, o zaman tekliyi kullanan tüm sınıflar artık ona sıkı sıkıya bağlıdır) ve onu değiştiremez veya uzatamazsınız. Bu konuda daha fazla bilgi almak için "Singleton anti-pattern" google'lı olabilir, örn. Singleton anti-pattern

Spring singleton kullanmak, gitmenin yoludur (Singleton tasarım modeli olarak DEĞİL, ancak genel bir kurucu ile uygulanan bir singleton fasulye ile), böylece Spring singleton fasulyesi kolayca test edilebilir ve onu kullanan sınıflar ona sıkıca bağlanmaz. daha ziyade, Spring singleton'u (bir arayüz olarak) ihtiyaç duyan tüm çekirdeklere enjekte eder ve tekli çekirdek, onu kullanan istemci sınıflarını etkilemeden herhangi bir zamanda başka bir uygulama ile değiştirilebilir.


1

İlkbaharda "singleton" fasulye fabrikası get örneğini kullanıyor, ardından önbelleğe al; hangi tekil tasarım modeli kesin olarak, örnek yalnızca statik get yönteminden alınabilir ve nesne hiçbir zaman genel olarak başlatılamaz.


1

ÖR: "çekirdek başına kap başına".

        <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;
    }
}

JAVA SINGLETON:

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> <property name = "name" value = "1-name"> </ property> </bean> <bean class = "com.spring4hibernate4.TestBean"> <constructor-arg name = "i" value = "10"> </constructor-arg> <property name = "name" value = "10 -name "> </property> </bean> </beans>
Hariprasad

1

Bahar tekli fasulye, 'çekirdek başına kap başına' olarak tanımlanır. Spring'deki Singleton kapsamı, aynı bellek konumundaki aynı nesnenin aynı fasulye kimliğine döndürüleceği anlamına gelir. Biri aynı sınıftan farklı kimliklerden birden fazla çekirdek oluşturursa, kap farklı nesneleri farklı kimliklere döndürür. Bu, anahtarın fasulye kimliği ve değerin bir yay kabındaki fasulye nesnesi olduğu bir anahtar değer eşlemesi gibidir. Singleton kalıbı, sınıf yükleyici başına belirli bir sınıfın yalnızca bir örneğinin oluşturulmasını sağlar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.