Является ли боб, созданный с помощью NEW, действительно синглтоном?

Я создал Spring Bean в классе конфигурации следующим образом:

@Bean
MyClass getMyClass() {
    MyClass mc = new MyClass()
    return mc;
}

Всякий раз, когда MyClass автоматически подключается в другой класс, который нуждается в его внедрении, всегда будет создавать новый объект в силу new в определении бина? Боб, созданный таким образом, настоящий синглтон?

3 ответа

Решение

Spring гарантирует, что все, что вы делаете в методе, отмеченном Bean аннотация это будет сделано только один раз. Об этом позаботятся заводы Internal Spring.

Конечно это зависит от scope но по умолчанию область действия singleton, Смотрите документы:

  1. Области применения
  2. боб
  3. Весенняя область по умолчанию синглтон или нет?

Небольшой пример, который должен помочь вам понять, как это работает:

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.LocalDateTime;
import java.util.Random;

@Configuration
public class SpringApp {

    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringApp.class);

        System.out.println(ctx.getBean(MyClass.class));
        System.out.println(ctx.getBean(MyClass.class));
        System.out.println(ctx.getBean(MyClass.class));
        System.out.println(ctx.getBean(MyClass.class));
    }

    @Bean
    public MyClass getMyClass() {
        System.out.println("Create instance of MyClass at " + LocalDateTime.now());
        MyClass myClass = new MyClass();

        return myClass;
    }
}

class MyClass {

    private int value = new Random().nextInt();

    @Override
    public String toString() {
        return super.toString() + " with values = " + value;
    }
}

печатает:

Create instance of MyClass at 2019-01-09T22:54:37.025
com.celoxity.spring.MyClass@32a068d1 with values = -1518464221
com.celoxity.spring.MyClass@32a068d1 with values = -1518464221
com.celoxity.spring.MyClass@32a068d1 with values = -1518464221
com.celoxity.spring.MyClass@32a068d1 with values = -1518464221

Когда вы определяете бин с областью действия protoype

@Scope("prototype")
@Bean
public MyClass getMyClass()

Приложение печатает:

Create instance of MyClass at 2019-01-09T22:57:12.585
com.celoxity.spring.MyClass@282003e1 with values = -677868705
Create instance of MyClass at 2019-01-09T22:57:12.587
com.celoxity.spring.MyClass@7fad8c79 with values = 18948996
Create instance of MyClass at 2019-01-09T22:57:12.587
com.celoxity.spring.MyClass@71a794e5 with values = 358780038
Create instance of MyClass at 2019-01-09T22:57:12.587
com.celoxity.spring.MyClass@76329302 with values = 868257220

В вашем примере да.

То, что произойдет практически, это то, что, когда весна запускается, она будет вызывать getMyClass() метод, который создаст экземпляр объекта. Затем Spring сохранит этот единственный экземпляр и вставит его во все остальные bean-компоненты, для которых требуется экземпляр MyClass.

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

Концепция Spring для одноэлементного bean-компонента сильно отличается от шаблона Singleton.

Объем синглтона Spring лучше всего описывается по контейнеру и по bean-компоненту.

Раздел 4.4.1

Это означает, что если вы создаете компонент , этот компонент обеспечивает свой жизненный цикл из Springконтейнера Spring IoC.Если вы хотите создать с помощью «NEW действительно одноэлементный компонент». У вас есть это через новый контейнер Spring Ioc. Позвольте мне проиллюстрировать это на примере.

       public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringApp.class);
        ApplicationContext ctxReallyNewOne = new AnnotationConfigApplicationContext(SpringApp.class);
        ApplicationContext ctx2ReallySecondOne = new AnnotationConfigApplicationContext(SpringApp.class);

        System.out.println(ThreadColors.Red + "Beans created via same Ioc container with same class");
        System.out.println(ctx.getBean(MyClass.class));
        System.out.println(ctx.getBean(MyClass.class));

        System.out.println(ThreadColors.Cyan + "Beans created via different Ioc container with SAME CLASS");
        System.out.println(ctxReallyNewOne.getBean(MyClass.class));
        System.out.println(ctx2ReallySecondOne.getBean(MyClass.class));

    }

После запуска этого кода в консоль записывается следующее.

Также, если вы хотите получить дату создания bean-компонента, не нужно использовать LocalDataTime.now(). Для этого лучше всего использовать «Жизненный цикл Spring Beans».

Жизненный цикл бобов Spring

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