Является ли боб, созданный с помощью NEW, действительно синглтоном?
Я создал Spring Bean в классе конфигурации следующим образом:
@Bean
MyClass getMyClass() {
MyClass mc = new MyClass()
return mc;
}
Всякий раз, когда MyClass
автоматически подключается в другой класс, который нуждается в его внедрении, всегда будет создавать новый объект в силу new
в определении бина? Боб, созданный таким образом, настоящий синглтон?
3 ответа
Spring
гарантирует, что все, что вы делаете в методе, отмеченном Bean
аннотация это будет сделано только один раз. Об этом позаботятся заводы Internal Spring.
Конечно это зависит от scope
но по умолчанию область действия singleton
, Смотрите документы:
Небольшой пример, который должен помочь вам понять, как это работает:
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-компоненту.
Это означает, что если вы создаете компонент , этот компонент обеспечивает свой жизненный цикл из 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».