用 NEW 创建的 spring bean 真的是单例吗

Is a spring bean created with NEW really a singleton

我在这样的配置 class 中创建了一个 spring bean:

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

每当 MyClass 在另一个需要它注入的 class 中自动装配时,它是否总是会凭借 bean 定义中的 new 创建一个新对象? 这样创建的bean是真正的单例吗?

Spring 保证无论你在用 Bean 注释的方法中做什么,它都只会执行一次。内部 Spring 工厂会处理这个问题。

当然这取决于 scope,但默认范围是 singleton。请参阅文档:

  1. Scopes
  2. Bean
  3. Is spring default scope singleton or not?

应该可以帮助您理解其工作原理的小示例:

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

当你用作用域定义bean时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

在你的例子中,是的。

实际上会发生的是,当Spring 启动时,它会调用getMyClass() 方法,该方法会新建一个对象的实例。 Spring 然后将保留该单个实例并将其注入到所有其他需要 MyClass 实例的 bean 中。

它将以这种方式工作,因为您没有在 bean 上声明范围——如其他答案所示,默认值为单例。

Spring's concept of a singleton bean is quite different from the Singleton pattern.

The scope of the Spring singleton is best described as per container and per bean

Section 4.4.1

这意味着如果您创建一个 spring bean,该 bean 会在 IoC Spring Container. 中提供其生命周期 如果你想用“NEW 真正的单例 bean”来创建。您可以通过一个新的 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.Does 的创建日期,则不需要使用 LocalDataTime.now() 。为此,最好使用“Spring Beans 的生命周期”。

The Lifecycle of Spring Beans