单例范围
如果使用 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...