Pola desain tunggal vs kacang tunggal dalam wadah musim semi

90

Seperti yang kita semua tahu kita memiliki bean sebagai singleton secara default di Spring container dan jika kita memiliki aplikasi web berdasarkan framework Spring maka dalam hal ini kita benar-benar perlu mengimplementasikan pola desain Singleton untuk menyimpan data global daripada hanya membuat bean melalui spring. .

Mohon bersabarlah jika saya tidak dapat menjelaskan apa yang sebenarnya ingin saya tanyakan.

Peeyush
sumber

Jawaban:

61

Kacang tunggal di musim semi dan pola tunggal sangat berbeda. Pola Singleton mengatakan bahwa satu dan hanya satu instance dari kelas tertentu yang akan dibuat per classloader.

Lingkup singleton Spring dideskripsikan sebagai "per container per bean". Ini adalah ruang lingkup definisi kacang ke satu instance objek per kontainer Spring IoC. Cakupan default di Spring adalah Singleton.

Meskipun cakupan default adalah tunggal, Anda dapat mengubah cakupan kacang dengan menentukan atribut cakupan <bean ../>elemen.

<bean id=".." class=".." scope="prototype" />
pengguna184794
sumber
12
@ user184794: per container per bean, artinya hanya ada satu classloader di spring container. jika ada dua atau lebih classloader di spring container, maka setiap classloader akan memiliki instance sendiri. Apakah itu berarti "per container per classloader per bean". mohon klarifikasi !!
Programmer Mati
4
saya pikir itu berarti bahwa wadah Spring akan menggunakan classloader tunggal yang dimilikinya. apa yang Anda lakukan di luar mekanisme Spring tidak relevan, yaitu Anda dapat membuat classloader Anda sendiri dan membuat instance kelas sebanyak yang Anda inginkan, tetapi jika Anda menggunakan container Spring, itu tidak akan membuat lebih dari satu instance
inor
1
Maka mereka tidak "sangat berbeda" seperti yang Anda nyatakan. Satu-satunya perbedaan adalah ruang lingkup - Spring container verses classloader
Zack Macomber
31

Lingkup tunggal di musim semi berarti instance tunggal dalam konteks Spring ..
Container Spring hanya mengembalikan instance yang sama berulang kali untuk panggilan berikutnya untuk mendapatkan bean.


Dan musim semi tidak mengganggu jika kelas kacang dikodekan sebagai tunggal atau tidak, pada kenyataannya jika kelas dikodekan sebagai tunggal yang konstruktornya sebagai pribadi, Spring menggunakan BeanUtils.instantiateClass (javadoc di sini ) untuk mengatur konstruktor agar dapat diakses dan dipanggil Itu.

Alternatifnya, kita dapat menggunakan atribut metode pabrik dalam definisi kacang seperti ini

    <bean id="exampleBean" class="example.Singleton"  factory-method="getInstance"/>
Vasanth
sumber
1
apakah Anda yakin memerlukan atribut metode pabrik? Saya cukup yakin Spring tahu cara mendapatkan instance meskipun konstruktornya bersifat pribadi (mungkin mencoba menelepon getInstance)
atau
Diskusi terkait tentang bagaimana Spring memanggil konstruktor pribadi di sini
Xiawei Zhang
22

Mari kita ambil contoh paling sederhana: Anda memiliki aplikasi dan Anda cukup menggunakan classloader default. Anda memiliki kelas yang, untuk alasan apa pun, Anda memutuskan bahwa kelas itu tidak boleh memiliki lebih dari satu contoh dalam aplikasi. (Pikirkan skenario di mana beberapa orang mengerjakan bagian aplikasi).

Jika Anda tidak menggunakan framework Spring, pola Singleton memastikan bahwa tidak akan ada lebih dari satu instance kelas dalam aplikasi Anda. Itu karena Anda tidak dapat membuat instance kelas dengan melakukan 'baru' karena konstruktornya bersifat pribadi. Satu-satunya cara untuk mendapatkan instance kelas adalah dengan memanggil beberapa metode statis kelas (biasanya disebut 'getInstance') yang selalu mengembalikan instance yang sama.

Mengatakan bahwa Anda menggunakan kerangka kerja Spring dalam aplikasi Anda, berarti selain cara biasa untuk mendapatkan instance kelas (metode baru atau statis yang mengembalikan instance kelas), Anda juga dapat meminta Spring untuk mendapatkan Anda sebuah instance dari kelas itu dan Spring akan memastikan bahwa setiap kali Anda memintanya untuk sebuah instance dari kelas itu, ia akan selalu mengembalikan instance yang sama, bahkan jika Anda tidak menulis kelas tersebut menggunakan pola Singleton. Dengan kata lain, meskipun kelas tersebut memiliki konstruktor publik, jika Anda selalu meminta Spring untuk instance kelas itu, Spring hanya akan memanggil konstruktor itu sekali selama masa pakai aplikasi Anda.

Biasanya jika Anda menggunakan Spring, Anda hanya boleh menggunakan Spring untuk membuat instance, dan Anda dapat memiliki konstruktor publik untuk kelas tersebut. Tetapi jika konstruktor Anda tidak bersifat pribadi, Anda tidak benar-benar mencegah siapa pun membuat instance baru dari kelas secara langsung, dengan melewati Spring.

Jika Anda benar-benar menginginkan satu instance kelas, bahkan jika Anda menggunakan Spring dalam aplikasi Anda dan menentukan kelas di Spring menjadi tunggal, satu-satunya cara untuk memastikan bahwa adalah juga mengimplementasikan kelas menggunakan pola Singleton. Itu memastikan bahwa akan ada satu instance, apakah orang menggunakan Spring untuk mendapatkan instance atau melewati Spring.

inor
sumber
13

Saya merasa " per kontainer per biji" sulit untuk dipahami . Saya akan mengatakan " satu kacang per id kacang dalam wadah ". Mari kita punya contoh untuk memahaminya. Kami memiliki Sampel kelas kacang. Saya telah mendefinisikan dua kacang dari kelas ini dalam definisi kacang, seperti:

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

Jadi ketika saya mencoba untuk mendapatkan kacang dengan id "id1", wadah pegas akan membuat satu kacang, men-cache-nya dan mengembalikan kacang yang sama dimana pernah direferensikan dengan id1. Jika saya mencoba mendapatkannya dengan id7, kacang lain akan dibuat dari kelas Sampel, kacang yang sama akan di-cache dan dikembalikan setiap kali Anda merujuknya dengan id7.

Ini tidak mungkin terjadi dengan pola Singleton. Dalam pola Singlton, satu objek per pemuat kelas selalu dibuat. Namun di Spring, membuat scope sebagai Singleton tidak membatasi container untuk membuat banyak instance dari class tersebut. Itu hanya membatasi pembuatan objek baru untuk ID yang sama lagi, mengembalikan objek yang dibuat sebelumnya ketika sebuah objek diminta untuk id yang sama . Referensi

Dexter
sumber
Dijelaskan dengan baik. Terima kasih!
Swapnil
12

Cakupan tunggal di Spring berarti bahwa kacang ini hanya akan dipakai sekali oleh Spring. Berbeda dengan lingkup prototipe (contoh baru setiap kali), lingkup permintaan (sekali per permintaan), lingkup sesi (sekali per sesi HTTP).

Lingkup singleton secara teknis tidak ada hubungannya dengan pola desain singleton. Anda tidak perlu mengimplementasikan bean Anda sebagai single agar bisa ditempatkan di scope singleton.

lexicore.dll
sumber
1
Koreksi saya jika saya salah jadi menurut Anda jika saya perlu mengimplementasikan objek apa pun sebagai tunggal sehingga tidak perlu menerapkan pola tunggal. Membuat kacang itu menggunakan Spring akan berhasil. Saya agak bingung sekarang dengan pemahaman saya terkait pola Desain Singleton dan cakupan Singleton dalam kerangka Spring.
Peeyush
1
Musim semi tidak memaksa Anda untuk menggunakan pola Singleton.
lexicore
2

Kacang tunggal di Musim Semi dan kelas berdasarkan pola desain Singleton sangat berbeda.

Pola tunggal memastikan bahwa satu dan hanya satu contoh dari kelas tertentu yang akan pernah dibuat per pemuat kelas dimana ruang lingkup kacang tunggal musim semi dijelaskan sebagai 'per kontainer per kacang'. Cakupan tunggal di Spring berarti bahwa kacang ini hanya akan dipakai sekali oleh Spring. Penampung pegas hanya mengembalikan contoh yang sama berulang kali untuk panggilan berikutnya untuk mendapatkan kacang.

JavaMave
sumber
13
Anda adalah 'maverick java', kan? Itu akan membuat pernyataan Anda, "Menemukan penjelasan dan contoh yang baik di ..." merupakan upaya tidak jujur ​​untuk menyembunyikan bahwa Anda menautkan ke situs web Anda sendiri. Tautan Anda tampaknya tidak penting untuk jawabannya. Saya menghapusnya, untuk menghindari jawaban dihapus sebagai spam. Harap baca FAQ tentang Promosi Mandiri sebelum memposting link lagi ke situs Anda. perhatikan juga bahwa tidak masalah bagi Anda untuk meletakkan tautan situs web Anda di profil Anda.
Andrew Barber
2

Ada perbedaan yang sangat mendasar di antara keduanya. Dalam kasus pola desain Singleton, hanya satu contoh kelas yang akan dibuat per classLoader sementara itu tidak terjadi dengan Spring singleton seperti di kemudian satu contoh kacang bersama untuk id yang diberikan per kontainer IoC dibuat.

Misalnya, jika saya memiliki kelas dengan nama "SpringTest" dan file XML saya terlihat seperti ini: -

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

Jadi sekarang di kelas utama jika Anda akan memeriksa referensi dari dua di atas itu akan mengembalikan false sesuai dengan dokumentasi Spring: -

Ketika kacang adalah tunggal, hanya satu contoh kacang bersama yang akan dikelola, dan semua permintaan kacang dengan id atau id yang cocok dengan definisi kacang itu akan menghasilkan satu contoh kacang tertentu dikembalikan oleh wadah Spring

Jadi seperti dalam kasus kami, kelasnya sama tetapi id yang kami berikan berbeda sehingga menghasilkan dua contoh berbeda yang dibuat.

hhhakki
sumber
2

Semua jawaban, setidaknya sejauh ini, berkonsentrasi pada penjelasan perbedaan antara pola desain dan Spring singleton dan tidak menjawab pertanyaan Anda yang sebenarnya: Haruskah pola desain Singleton digunakan atau Spring singleton bean? apa yang lebih baik?

Sebelum saya menjawab, izinkan saya menyatakan bahwa Anda dapat melakukan keduanya. Anda dapat mengimplementasikan kacang sebagai pola desain Singleton dan menggunakan Spring untuk memasukkannya ke dalam kelas klien sebagai kacang tunggal Spring.

Sekarang, jawaban atas pertanyaannya sederhana: Jangan gunakan pola desain Singleton!
Gunakan kacang tunggal Spring yang diimplementasikan sebagai kelas dengan konstruktor publik.
Mengapa? Karena pola desain Singleton dianggap anti pola. Terutama karena pengujian yang rumit. (Dan jika Anda tidak menggunakan Spring untuk menyuntikkannya, semua kelas yang menggunakan singleton sekarang terikat erat padanya), dan Anda tidak dapat mengganti atau memperpanjangnya. Seseorang dapat google "anti-pola Singleton" untuk mendapatkan info lebih lanjut tentang ini, misalnya anti-pola Singleton

Menggunakan Spring singleton adalah cara yang harus dilakukan (dengan kacang tunggal diimplementasikan BUKAN sebagai pola desain Singleton, melainkan dengan konstruktor publik) sehingga kacang tunggal Spring dapat dengan mudah diuji dan kelas yang menggunakannya tidak digabungkan erat dengannya , tetapi, Spring menyuntikkan singleton (sebagai antarmuka) ke semua kacang yang membutuhkannya, dan kacang tunggal dapat diganti kapan saja dengan implementasi lain tanpa memengaruhi kelas klien yang menggunakannya.

inor
sumber
1

"singleton" di musim semi menggunakan instance get factory get, lalu menyimpannya dalam cache; dengan pola desain tunggal yang ketat, instance hanya dapat diambil dari metode get statis, dan objek tidak pernah dapat digunakan secara publik.

lwpro2
sumber
1

EX: "per kontainer per biji".

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

TUNGGAL JAWA:

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());
    }
Hariprasad
sumber
<bean class = "com.spring4hibernate4.TestBean"> <constructor-arg name = "i" value = "1"> </constructor-arg> <property name = "name" value = "1-name"> </ properti> </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

Kacang tunggal musim semi digambarkan sebagai 'per wadah per biji'. Lingkup tunggal di Spring berarti objek yang sama di lokasi memori yang sama akan dikembalikan ke bean id yang sama. Jika seseorang membuat beberapa bean dari id berbeda dari kelas yang sama maka kontainer akan mengembalikan objek yang berbeda ke id yang berbeda. Ini seperti pemetaan nilai kunci di mana kuncinya adalah id kacang dan nilai adalah objek kacang dalam satu wadah pegas. Dimana pola Singleton memastikan bahwa satu dan hanya satu instance dari kelas tertentu yang akan dibuat per classloader.

Sibaprasad Sahoo
sumber