Jak wszyscy wiemy, w kontenerze Spring domyślnie mamy ziarna jako singleton i jeśli mamy aplikację internetową opartą na frameworku Spring, to w takim przypadku naprawdę musimy zaimplementować wzorzec projektowy Singleton do przechowywania danych globalnych, a nie tylko do tworzenia fasoli do wiosny .
Proszę o wyrozumiałość, jeśli nie jestem w stanie wyjaśnić, o co właściwie chciałem zapytać.
źródło
Zakres pojedynczy w spring oznacza pojedynczą instancję w kontekście
Spring. Kontener Spring po prostu zwraca tę samą instancję raz po raz dla kolejnych wywołań w celu pobrania komponentu bean.
I spring nie przejmuje się tym, czy klasa fasoli jest zakodowana jako singleton czy nie, w rzeczywistości, jeśli klasa jest zakodowana jako singleton, której konstruktor jest prywatny, Spring używa BeanUtils.instantiateClass (javadoc tutaj ), aby ustawić konstruktor na dostępność i wywołać to.
Alternatywnie, możemy użyć atrybutu metody fabrycznej w takiej definicji fasoli
<bean id="exampleBean" class="example.Singleton" factory-method="getInstance"/>
źródło
Weźmy najprostszy przykład: masz aplikację i po prostu używasz domyślnego modułu ładującego klasy. Masz klasę, która z jakiegokolwiek powodu decydujesz, że nie powinna mieć więcej niż jednej instancji w aplikacji. (Pomyśl o scenariuszu, w którym kilka osób pracuje nad fragmentami aplikacji).
Jeśli nie korzystasz ze środowiska Spring, wzorzec Singleton zapewnia, że w Twojej aplikacji nie będzie więcej niż jedno wystąpienie klasy. Dzieje się tak, ponieważ nie można utworzyć instancji klasy, wykonując polecenie „new”, ponieważ konstruktor jest prywatny. Jedynym sposobem uzyskania instancji klasy jest wywołanie jakiejś statycznej metody klasy (zwykle nazywanej „getInstance”), która zawsze zwraca tę samą instancję.
Powiedzenie, że używasz frameworka Spring w swojej aplikacji, oznacza po prostu, że oprócz zwykłych sposobów uzyskiwania instancji klasy (nowych lub statycznych metod, które zwracają instancję klasy), możesz również poprosić Springa o uzyskanie instancja tej klasy i Spring zapewni, że za każdym razem, gdy poprosisz ją o instancję tej klasy, zawsze zwróci tę samą instancję, nawet jeśli klasa nie została napisana przy użyciu wzorca Singleton. Innymi słowy, nawet jeśli klasa ma konstruktora publicznego, jeśli zawsze prosisz Springa o instancję tej klasy, Spring wywoła ten konstruktor tylko raz w czasie życia aplikacji.
Zwykle, jeśli używasz Springa, powinieneś używać Springa tylko do tworzenia instancji i możesz mieć publiczny konstruktor dla klasy. Ale jeśli twój konstruktor nie jest prywatny, tak naprawdę nie uniemożliwiasz nikomu bezpośredniego tworzenia nowych instancji klasy, omijając Spring.
Jeśli naprawdę chcesz mieć jedną instancję klasy, nawet jeśli używasz Springa w swojej aplikacji i zdefiniujesz klasę w Spring jako singleton, jedynym sposobem na to jest zaimplementowanie klasy przy użyciu wzorca Singleton. Gwarantuje to, że będzie jedna instancja, niezależnie od tego, czy ludzie używają Springa do uzyskania instancji, czy też pomijają Spring.
źródło
Uważam, że „ na pojemnik na ziarno” jest trudne do zrozumienia . Powiedziałbym „ jedno ziarno na identyfikator ziarna w pojemniku ”. Mamy przykład, aby to zrozumieć. Mamy próbkę klasy fasoli. Zdefiniowałem dwie fasole z tej klasy w definicji fasoli, takie jak:
<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>
Więc kiedy kiedykolwiek spróbuję uzyskać ziarno o identyfikatorze „id1”, pojemnik sprężynowy utworzy jedno ziarno, zapisze je w pamięci podręcznej i zwróci to samo ziarno, o ile kiedykolwiek zostało określone przez id1. Jeśli spróbuję uzyskać to za pomocą id7, inny bean zostanie utworzony z klasy Sample, to samo będzie buforowane i zwracane za każdym razem, gdy odwołasz to z id7.
Jest to mało prawdopodobne w przypadku wzorca Singleton. We wzorcu Singlton zawsze tworzony jest jeden obiekt na program ładujący klasy. Jednak wiosną ustawienie zakresu jako Singleton nie ogranicza kontenera do tworzenia wielu instancji z tej klasy. Po prostu ponownie ogranicza tworzenie nowych obiektów dla tego samego identyfikatora, zwracając wcześniej utworzony obiekt, gdy zażądano obiektu o tym samym identyfikatorze . Odniesienie
źródło
Zakres singletona w Spring oznacza, że instancja tego ziarna zostanie utworzona tylko raz do Spring. W przeciwieństwie do zakresu prototypu (za każdym razem nowa instancja), zakres żądania (raz na żądanie), zakres sesji (raz na sesję HTTP).
Zakres singleton nie ma technicznie nic wspólnego z wzorcem projektowym singleton. Nie musisz implementować swoich bean jako singletonów, aby zostały umieszczone w zakresie singleton.
źródło
Ziarna singletona na wiosnę i klasy oparte na wzorcu projektowym Singleton są zupełnie inne.
Wzorzec singleton gwarantuje, że jedno i tylko jedno wystąpienie określonej klasy zostanie kiedykolwiek utworzone dla modułu ładującego klasy, przy czym zakres pojedynczego komponentu bean Spring jest opisany jako „na kontener na ziarno”. Zakres singleton w Spring oznacza, że instancja tego ziarna zostanie utworzona tylko raz do Spring. Spring container po prostu zwraca tę samą instancję raz po raz dla kolejnych wywołań w celu pobrania ziarna.
źródło
Jest między nimi bardzo fundamentalna różnica. W przypadku wzorca projektowego Singleton, tylko jedna instancja klasy zostanie utworzona na classLoader, podczas gdy tak nie jest w przypadku Spring singleton, ponieważ później tworzona jest jedna współużytkowana instancja fasoli dla danego identyfikatora na kontener IoC.
Na przykład, jeśli mam klasę o nazwie „SpringTest”, a mój plik XML wygląda mniej więcej tak: -
<bean id="test1" class="com.SpringTest" scope="singleton"> --some properties here </bean> <bean id="test2" class="com.SpringTest" scope="singleton"> --some properties here </bean>
Więc teraz w głównej klasie, jeśli sprawdzisz odniesienie do powyższych dwóch, zwróci to fałsz zgodnie z dokumentacją Springa: -
Tak jak w naszym przypadku, klasy są takie same, ale podane przez nas identyfikatory są różne, co powoduje utworzenie dwóch różnych instancji.
źródło
Wszystkie odpowiedzi, przynajmniej do tej pory, koncentrują się na wyjaśnieniu różnicy między wzorcem projektowym a wiosennym singletonem i nie odnoszą się do twojego rzeczywistego pytania: Czy należy użyć wzorca projektowego Singleton, czy też ziarna singleton Spring? co jest lepsze?
Zanim odpowiem, powiem tylko, że możesz zrobić jedno i drugie. Możesz zaimplementować komponent bean jako wzorzec projektowy Singleton i użyć Spring, aby wstrzyknąć go do klas klienta jako pojedynczy bean Spring.
Teraz odpowiedź na pytanie jest prosta: nie używaj wzorca projektowego Singleton!
Użyj pojedynczego komponentu bean Spring zaimplementowanego jako klasa z publicznym konstruktorem.
Czemu? Ponieważ wzorzec projektowy Singleton jest uważany za anty-wzorzec. Głównie dlatego, że komplikuje testowanie. (A jeśli nie użyjesz Springa do wstrzyknięcia, to wszystkie klasy używające singletona są teraz ściśle z nim powiązane) i nie możesz go zastąpić ani rozszerzyć. Można wygooglować "Singleton anti-pattern", aby uzyskać więcej informacji na ten temat, np. Singleton anti-pattern
Korzystanie z singletona Spring jest najlepszym rozwiązaniem (z pojedynczym komponentem bean zaimplementowanym NIE jako wzorzec projektowy Singleton, ale raczej z publicznym konstruktorem), aby można było łatwo przetestować pojedynczy komponent bean Spring, a klasy, które go używają, nie są z nim ściśle powiązane , ale raczej Spring wstrzykuje singleton (jako interfejs) do wszystkich ziaren, które go potrzebują, i można je zastąpić w dowolnym momencie inną implementacją bez wpływu na klasy klienta, które go używają.
źródło
"singleton" na wiosnę używa instancji pobierania z fabryki fasoli, a następnie buforuje ją; który wzorzec projektowy singleton jest ściśle, instancja może zostać pobrana tylko ze statycznej metody get, a obiekt nigdy nie może zostać publicznie utworzony.
źródło
EX: „na pojemnik na ziarno”.
<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()); }
źródło
Pojedyncze ziarna wiosenne opisywane są jako „na pojemnik na ziarno”. Zasięg singletonowy w Spring oznacza, że ten sam obiekt w tej samej lokalizacji pamięci zostanie zwrócony do tego samego identyfikatora fasoli. Jeśli tworzy się wiele komponentów bean o różnych identyfikatorach tej samej klasy, to container zwraca różne obiekty do różnych identyfikatorów. Jest to podobne do mapowania wartości klucza, w którym klucz to identyfikator fasoli, a wartość to obiekt fasoli w jednym pojemniku sprężynowym. Gdzie jako wzorzec Singleton zapewnia, że jedno i tylko jedno wystąpienie określonej klasy zostanie kiedykolwiek utworzone na program ładujący klasy.
źródło