单例范围

如果使用 singleton 范围定义 bean,则只会在 Spring 容器中初始化一个对象实例。对此 bean 的所有请求都将返回相同的共享实例。这是定义 bean 时的默认范围。

给出以下 MyBean 类:

public class MyBean {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyBean.class);
    private String property;

    public MyBean(String property) {
        this.property = property;
        LOGGER.info("Initializing {} bean...", property);
    }

    public String getProperty() {
        return this.property;
    }

    public void setProperty(String property) {
        this.property = property;
    }
}

我们可以用 @Bean 注释定义一个单例 bean:

@Configuration
public class SingletonConfiguration {

    @Bean
    public MyBean singletonBean() {
        return new MyBean("singleton");
    } 
}

以下示例从 Spring 上下文中检索两次相同的 bean:

MyBean singletonBean1 = context.getBean("singletonBean", MyBean.class);
singletonBean1.setProperty("changed property");

MyBean singletonBean2 = context.getBean("singletonBean", MyBean.class);

记录 singletonBean2 属性时,将显示消息 changed property ,因为我们只检索了相同的共享实例。

由于实例是在不同组件之间共享的,因此建议为无状态对象定义单例范围。

懒惰的单例豆

默认情况下,单例 bean 是预先实例化的。因此,将在创建 Spring 容器时创建共享对象实例。如果我们启动应用程序,将显示 “正在初始化单例 bean …” 消息。

如果我们不希望预先实例化 bean,我们可以将 @Lazy 注释添加到 bean 定义中。这将阻止在第一次请求 bean 之前创建 bean。

@Bean
@Lazy
public MyBean lazySingletonBean() {
    return new MyBean("lazy singleton");
}

现在,如果我们启动 Spring 容器,则不会出现 “正在初始化 lazy singleton bean …” 消息。在第一次请求 bean 之前,不会创建 bean:

logger.info("Retrieving lazy singleton bean...");
context.getBean("lazySingletonBean");

如果我们运行应用程序同时定义了 singleton 和 lazy singleton bean,它将产生以下消息:

Initializing singleton bean...
Retrieving lazy singleton bean...
Initializing lazy singleton bean...