Шаблон дизайну синглтон проти квасолі синглтон у контейнері Spring


90

Як ми всі знаємо, ми за замовчуванням використовуємо боб як синглтон у контейнері Spring, і якщо у нас є веб-додаток, засноване на структурі Spring, то в такому випадку нам дійсно потрібно реалізовувати шаблон проектування Singleton для зберігання глобальних даних, а не просто створювати компонент через spring .

Будь ласка, потерпіть зі мною, якщо я не можу пояснити, про що я насправді хотів запитати.

Відповіді:


60

Насіннєвий боб навесні та одиночний візерунок досить сильно відрізняються. Шаблон Singleton говорить, що для кожного завантажувача класів коли-небудь буде створений один і лише один екземпляр певного класу.

Сфера дії одномісного джерела Spring описується як "на контейнер на боб". Це сфера визначення компонента для одного екземпляра об’єкта на контейнер Spring IoC. Областю за замовчуванням у Spring є Singleton.

Незважаючи на те, що за замовчуванням область дії є односторонньою, ви можете змінити область дії компонента, вказавши атрибут scope <bean ../>елемента.

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

12
@ user184794: на контейнер на компонент, що означає, що в Spring контейнері є лише один завантажувач класів. якщо в Spring контейнері є два або більше завантажувачів класів, тоді кожен завантажувач класів матиме власний екземпляр. Чи означає це "на контейнер на завантажувач класів на боб". люб'язно уточнюйте !!
Dead Programmer

4
я думаю, це означає, що контейнер Spring використовуватиме один завантажувач класів, яким він володіє. те, що ви робите поза механізмом Spring, не актуально, тобто ви можете створювати власні завантажувачі класів і створювати стільки екземплярів класу, скільки забажаєте, але якщо ви пройдете контейнер Spring, це не створить більше одного екземпляра
inor

1
Тоді вони не "зовсім різні", як ви заявляєте. Єдина відмінність - сфера застосування - завантажувач стихів Spring Spring
Зак Макомбер

30

Обсяг Singleton в Spring означає один екземпляр у контексті
Spring. Контейнер Spring просто повертає той самий екземпляр знову і знову для наступних викликів для отримання компонента.


І Spring не заважає, якщо клас компонента кодується як одиночний чи ні, насправді, якщо клас кодується як одиночний, конструктор якого як приватний, Spring використовує BeanUtils.instantiateClass ( тут javadoc ), щоб встановити конструктор доступним та викликати це.

Крім того, ми можемо використовувати атрибут factory-method у визначенні компонента, як це

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

1
ви впевнені, що вам потрібен атрибут factory-method? я майже впевнений, що Spring знає, як отримати екземпляр, навіть якщо конструктор є приватним (можливо, намагається викликати getInstance)
inor

Пов'язана дискусія про те, як Spring закликає тут
Xiawei Zhang

21

Візьмемо найпростіший приклад: у вас є програма, і ви просто використовуєте завантажувач класів за замовчуванням. У вас є клас, який з будь-якої причини вирішує, що він не повинен мати більше одного екземпляра в програмі. (Подумайте про сценарій, коли декілька людей працюють над частинами програми).

Якщо ви не використовуєте фреймворк Spring, шаблон Singleton гарантує, що у вашій програмі не буде більше одного екземпляра класу. Це тому, що ви не можете створити екземпляри екземплярів класу, роблячи 'new', оскільки конструктор є приватним. Єдиний спосіб отримати екземпляр класу - це викликати якийсь статичний метод класу (зазвичай його називають 'getInstance'), який завжди повертає той самий екземпляр.

Сказати, що ви використовуєте фреймворк Spring у своєму додатку, просто означає, що на додаток до звичайних способів отримання екземпляра класу (нових або статичних методів, які повертають екземпляр класу), ви також можете попросити Spring отримати вас екземпляр цього класу та Spring забезпечують, що всякий раз, коли ви запитуєте його про екземпляр цього класу, він завжди повертає той самий екземпляр, навіть якщо ви не писали клас за шаблоном Singleton. Іншими словами, навіть якщо клас має відкритий конструктор, якщо ви завжди запитуєте у Spring екземпляр цього класу, Spring буде викликати цей конструктор лише один раз протягом життя вашої програми.

Зазвичай, якщо ви використовуєте Spring, ви повинні використовувати Spring лише для створення екземплярів, і ви можете мати загальнодоступний конструктор для класу. Але якщо ваш конструктор не є приватним, ви насправді нікому не заважаєте створювати нові екземпляри класу безпосередньо, минаючи Spring.

Якщо ви дійсно хочете одиничний екземпляр класу, навіть якщо ви використовуєте Spring у своєму додатку і визначаєте клас у Spring як синглтон, єдиний спосіб забезпечити це також реалізацію класу за допомогою шаблону Singleton. Це гарантує наявність одного екземпляра, незалежно від того, чи використовують люди Spring, щоб отримати екземпляр, або обходять Spring.


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>

Отже, коли я коли-небудь намагаюся отримати бін з ідентифікатором "id1", контейнер spring створить один бін, кешує його і поверне той самий бін, де коли-небудь згадувалося з id1. Якщо я спробую отримати його за допомогою id7, з класу Sample буде створено інший компонент, який буде кешовано та повертатися кожного разу, коли ви посилаєтеся на це з id7.

Це малоймовірно для шаблону Singleton. У шаблоні Singlton завжди створюється один об'єкт на завантажувач класу. Однак навесні, створення області дії як Singleton не обмежує контейнер від створення багатьох примірників з цього класу. Він просто обмежує створення нового об’єкта для того самого ідентифікатора знову, повертаючи раніше створений об’єкт, коли об’єкт запитується для того самого ідентифікатора . Довідково


Добре пояснили. Дякую!
Swapnil

12

Діапазон Singleton у Spring означає, що цей компонент буде створений лише один раз для Spring. На відміну від області прототипу (кожен раз новий екземпляр), область запиту (один раз на запит), область сесії (один раз на сеанс HTTP).

Область застосування Singleton технічно не має нічого спільного з шаблоном дизайну singleton. Вам не потрібно реалізовувати свої боби як одиночні, щоб їх можна було помістити в одиночну область.


1
Виправте мене, якщо я помиляюся, тому, на вашу думку, якщо мені потрібно реалізувати будь-який об'єкт як синглтон, тож немає необхідності реалізовувати шаблон синглтона. Створення цього бобу за допомогою Spring буде працювати. Зараз я трохи плутаюся зі своїм розумінням, пов'язаним із шаблоном дизайну Singleton та сферою Singleton у рамках Spring.
Peeyush

1
Весна не змушує вас використовувати шаблон Singleton.
lexicore

2

Насіннєві боби навесні та класи, що базуються на шаблоні дизайну Singleton, досить різні.

Шаблон Singleton гарантує, що для кожного завантажувача класів коли-небудь буде створений один і лише один екземпляр певного класу, де як область сприйняття Singleton-компонента Spring описується як "на контейнер на bean". Діапазон Singleton у Spring означає, що цей компонент буде створений лише один раз для Spring. Контейнер Spring просто повертає той самий екземпляр знову і знову для наступних викликів, щоб отримати компонент.


13
Ви "java maverick", так? Це зробило б вашу заяву "Знайшли гарне пояснення та приклад на ..." нечесною спробою приховати, що ви посилаєтесь на свій власний веб-сайт. Ваше посилання, здається, не є важливим для відповіді. Я видаляю його, щоб уникнути видалення відповіді як спаму. Будь ласка, прочитайте Поширені запитання щодо самореклами, перш ніж розміщувати посилання на свій веб-сайт. також зауважте, що для вас цілком нормально розміщувати посилання на свій веб-сайт у своєму профілі.
Ендрю Барбер

2

Існує дуже принципова різниця між ними. У випадку шаблону проектування Singleton для кожного classLoader буде створений лише один екземпляр класу, тоді як цього не трапляється з Spring singleton, як у наступному спільному екземплярі bean для даного ідентифікатора на контейнер IoC.

Наприклад, якщо у мене є клас із назвою "SpringTest", і мій 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>

Отже, зараз у основному класі, якщо ви перевірите посилання на вищезазначені два, він поверне false, як згідно з документацією Spring: -

Коли компонент bean є синглтоном, буде керуватися лише одним спільним екземпляром компонента, і всі запити на компоненти з ідентифікаторами або ідентифікаторами, що відповідають цьому визначенню компонента, призведуть до того, що контейнер Spring поверне один конкретний екземпляр компонента

Отже, як і в нашому випадку, класи однакові, але ідентифікатори, які ми надали, різні, отже, створюються два різні екземпляри.


1

"singleton" навесні використовує екземпляр фабрики get bean, а потім кешує його; який односторонній шаблон дизайну суворо, екземпляр можна отримати лише за допомогою статичного методу get, і об’єкт ніколи не може бути публічно створений.


1

ПРИКЛАД: "на контейнер на боб".

        <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> <property name = "name" value = "1-name"> </ властивість> </bean> <bean class = "com.spring4hibernate4.TestBean"> <constructor-arg name = "i" value = "10"> </constructor-arg> <property name = "name" value = "10 -name "> </property> </bean> </beans>
Харіпрасад,

1

Весняний одиночний боб описується як "на контейнер на боб". Одиночна область дії в Spring означає, що той самий об'єкт в одному і тому ж місці пам'яті буде повернутий до того самого ідентифікатора компонента. Якщо один створює декілька компонентів різних ідентифікаторів одного класу, тоді контейнер поверне різні об'єкти до різних ідентифікаторів. Це як відображення значення ключа, де ключ - ідентифікатор компонента, а значення - об’єкт компонента в одному контейнері Spring. Де як шаблон Singleton гарантує, що для кожного завантажувача класів буде коли-небудь створений один і лише один екземпляр певного класу.


1

Усі відповіді, принаймні поки, зосереджені на поясненні різниці між шаблоном дизайну та Spring Singleton і не стосуються вашого фактичного питання: Чи слід використовувати шаблон дизайну Singleton або Spring Singlebel Bean? що краще?

Перш ніж я відповім, дозвольте мені просто сказати, що ви можете зробити і те, і інше. Ви можете реалізувати bean як шаблон дизайну Singleton і використовувати Spring, щоб вводити його в клієнтські класи як Single single bean Spring.

Тепер відповідь на запитання проста: не використовуйте шаблон дизайну Singleton!
Використовуйте одиночний бін Spring, реалізований як клас із відкритим конструктором.
Чому? Оскільки шаблон дизайну Singleton вважається анти-шаблоном. Здебільшого тому, що це ускладнює тестування. (І якщо ви не використовуєте Spring, щоб вводити його, тоді всі класи, які використовують синглтон, тепер тісно пов'язані з ним), і ви не можете замінити або розширити його. Можна погуглити "Singleton anti-pattern", щоб отримати більше інформації про це, наприклад, Singleton anti-pattern

Використання Spring Singleton - це шлях (з однобітовим компонентом, реалізованим НЕ як шаблон дизайну Singleton, а скоріше із загальнодоступним конструктором), так що Spring Singleton bean може бути легко перевірений, а класи, які його використовують, не є тісно пов'язаними з ним , а навпаки, Spring вводить синглтон (як інтерфейс) у всі компоненти, які йому потрібні, і синглтон-компонент може бути замінений у будь-який час іншою реалізацією, не впливаючи на клієнтські класи, які його використовують.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.