Весной по умолчанию сфера синглтон или нет?

Не могли бы вы объяснить, почему Spring создает два объекта для конфигурации bean-компонентов, показанных ниже, поскольку по умолчанию область действия Spring по умолчанию - singleton?

Конфигурация Spring здесь:

<bean id="customer" class="jp.ne.goo.beans.Customer"> 
    <property name="custno" value="100"></property>
    <property name="custName" value="rajasekhar"> </property>
</bean>
<bean id="customer2" class="jp.ne.goo.beans.Customer"> 
    <property name="custno" value="200"></property> 
    <property name="custName" value="siva"></property> 
</bean>

9 ответов

Область Spring по умолчанию - синглтон. Просто ваша идея о том, что значит быть одиночкой, не соответствует тому, как Spring определяет синглтоны.

Если вы скажете Spring сделать два отдельных bean-компонента с разными идентификаторами и одним и тем же классом, то вы получите два отдельных bean-компонента, каждый с одноэлементной областью действия. Все одноэлементная область действия означает, что когда вы ссылаетесь на что-то с тем же идентификатором, вы получаете тот же экземпляр компонента.

Вот как документация Spring определяет одноэлементную область:

Управляется только один общий экземпляр одноэлементного компонента, и все запросы на компоненты с идентификатором или идентификаторами, соответствующими определению этого компонента, приводят к тому, что один конкретный экземпляр компонента возвращается контейнером Spring.

Одиночная область означает, что при использовании одного и того же идентификатора получается один и тот же компонент, то есть все Проверка того, что никакие два идентификатора, ссылающиеся на один и тот же класс, не помешают использовать карты в качестве bean-компонентов, и будет затруднена при использовании прокси-компонентов с BeanFactories. Для Spring для полиции это потребовало бы большого количества работы для небольшой выгоды, вместо этого она доверяет пользователям знать, что они делают.

Способ определить два имени для одного и того же компонента - использовать псевдоним:

В самом определении bean-компонента вы можете указать более одного имени для bean-компонента, используя комбинацию до одного имени, указанного в атрибуте id, и любого количества других имен в атрибуте name. Эти имена могут быть эквивалентными псевдонимами одного и того же компонента и могут быть полезны в некоторых ситуациях, например, позволяя каждому компоненту в приложении ссылаться на общую зависимость, используя имя компонента, специфичное для самого компонента.

Однако указание всех псевдонимов, в которых фактически определен компонент, не всегда адекватно. Иногда желательно ввести псевдоним для компонента, который определен в другом месте. Это обычно имеет место в больших системах, где конфигурация разделена между каждой подсистемой, каждая подсистема имеет свой собственный набор определений объектов. В метаданных конфигурации на основе XML вы можете использовать этот элемент для достижения этой цели.

Так что, если вы добавите имя в конфигурации бина:

<bean id="customer" name="customer2" 
    class="jp.ne.goo.beans.Customer">
</bean>

или создайте псевдоним для bean-компонента, определенного в другом месте:

<alias name="customer" alias="customer2"/>

тогда "customer" и "customer2" будут ссылаться на один и тот же экземпляр компонента.

Область Spring по умолчанию - singleton, и она создаст один объект для всех экземпляров, если вы явно не укажете область, которая будет прототипом. Вы не опубликовали весеннюю конфигурацию. Пожалуйста, отправьте это, это даст лучшую идею.

В SPring Singleton ссылается на Один компонент на контейнер Spring, где, как в Java, Singleton ссылается на один объект на загрузчик классов.

Так что Spring Singleton - это не то же самое, что Java Singleton. Не путайся между этими двумя.

Вы путаете две разные концепции.

Слово "синглтон" весной используется для области действия компонента, что означает, что компонент будет создан только один раз для всего приложения.

Обычное значение синглтона относится к шаблону GOF. Это объектно-ориентированный шаблон, гарантирующий, что будет существовать только один экземпляр класса (по крайней мере, в области действия classLoader).

Spring Singleton Bean Не работает как Java Singleton.

Если мы напишем

ApplicationContext ctx = new ClassPathXmlApplicationContext("MyConfig.xml");
        Customer obj1= (Customer) ctx.getBean("customer");
        Customer obj2 = (Customer) ctx.getBean("customer2");
        System.out.println(obj1 == obj2);
        System.out.println(obj1+ "::" + obj2);

Если мы увидим результат, он вернет 2 разных экземпляра. Согласно Spring DocsBean является одноэлементным, будет управляться только один общий экземпляр, и все компоненты запроса с идентификатором или идентификатором, соответствующим определению этого компонента. Здесь доступны 2 разных ID.

Контейнер Spring как управляющая пара ключ-значение, ключ как идентификатор / имя, а значение - bean.

Вы объявляете два боба одного класса. Это не то же самое.

@Component("springTestClass")
public class SpringTestClass{
     private int randomNumber = 0;
     public SpringTestClass(){
       randomNumber = new Random().nextInt(2000);
     }

     public int getRandomNumber(){
       return this.randomNumber;
     }

}

И попробуйте получить доступ к этому бину в двух местах, число будет одинаковым. Но вы создали два отдельных компонента.

Если вы хотите проверить, работает ли это, попробуйте:

public class Main{
   public static void main(String[] args){
     ApplicationContext ctx = ....;
     SpringTestClass testObject1 = (SpringTestClass)ctx.getBean("springTestClass");
     SpringTestClass testObject2 = (SpringTestClass)ctx.getBean("springTestClass");

    System.out.println(testObject1.getRandomNumber() == testObject2.getRandomNumber());
   }
}

Этот код должен возвращать true, если это тот же экземпляр; Но в SpringTestClass вы можете добавить аннотацию @Scope("prototype"). Выход будет ложным

Как уже упоминалось, два бина должны быть созданы из кода, который вы разместили. Синглтоны определяются следующим образом (из документации Spring: Singleton Scope)

Управляется только один общий экземпляр одноэлементного компонента, и все запросы на компоненты с идентификатором или идентификаторами, соответствующими определению этого компонента, приводят к тому, что один конкретный экземпляр компонента возвращается контейнером Spring.

Чтобы внести ясность в это, значение, стоящее за "общим экземпляром", поясняется в параграфе, который следует за приведенным выше

все последующие запросы и ссылки для этого именованного компонента возвращают кешированный объект

При создании одноэлементного компонента создается и кэшируется только один объект компонента. Это относится только к бобу, а не к тому классу, экземпляром которого может быть боб. Например,

<bean id="myBean" class="myPackage.myClass" />

<bean id="myOtherBean1 class="myPackage.myOtherClass1">
    <property name="beanReference1" ref="myBean" />
</bean>
<bean id="myOtherBean2 class="myPackage.myOtherClass2">
    <property name="beanReference2" ref="myBean" />
</bean>

В этой составленной конфигурации "myOtherBean1" и "myOtherBean2" имеют ссылки на один и тот же компонент "myBean", поэтому один и тот же экземпляр "myPackage.myClass". Если вы изменили код для добавления второго компонента "myPackage.myClass", он будет отличаться от "myBean".

Чтобы полностью понять это, также обратитесь к другой области Spring: прототип. Из документации Spring для Prototype Scope:

Не единственная прототипная область развертывания bean-компонента приводит к созданию нового экземпляра bean-компонента каждый раз, когда делается запрос для этого конкретного bean-компонента.

Это означает, что если бы мы использовали тот же Spring XML, что и выше, "myOtherBean1" и "myOtherBean2" каждый получал бы свои собственные отличные копии "myBean", который все еще является просто экземпляром "myPackage.myClass".

В следующем примере показан аннотированный метод @Bean, вызываемый дважды:

@Configuration
public class AppConfig {

    @Bean
    public ClientService clientService1() {
        ClientServiceImpl clientService = new ClientServiceImpl();
        clientService.setClientDao(clientDao());
        return clientService;
    }

    @Bean
    public ClientService clientService2() {
        ClientServiceImpl clientService = new ClientServiceImpl();
        clientService.setClientDao(clientDao());
        return clientService;
    }

    @Bean
    public ClientDao clientDao() {
        return new ClientDaoImpl();
    }

}

clientDao () вызывался один раз в clientService1() и один раз в clientService2(). Поскольку этот метод создает новый экземпляр ClientDaoImpl и возвращает его, вы обычно ожидаете иметь 2 экземпляра (по одному для каждой службы). Это определенно было бы проблематично: в Spring экземпляры bean-компонентов по умолчанию имеют одноэлементную область видимости. В этом и заключается магия: все классы @Configuration подклассируются во время запуска с помощью CGLIB. В подклассе дочерний метод сначала проверяет контейнер на наличие кэшированных (ограниченных) bean-компонентов, прежде чем он вызывает родительский метод и создает новый экземпляр. Обратите внимание, что начиная с Spring 3.2 больше нет необходимости добавлять CGLIB в ваш путь к классам, поскольку классы CGLIB были переупакованы в org.springframework.cglib и включены непосредственно в JAR-файл Spring-Core.

Spring область действия по умолчанию - singleton. После того, как компонент будет создан, один и тот же объект будет использоваться на протяжении всего его жизненного цикла.

Другие вопросы по тегам