原型范围
在 Spring 容器启动时不预先创建原型范围的 bean。相反,每次将检索此 bean 的请求发送到容器时,都会创建一个新的实例。建议将此范围用于有状态对象,因为其状态不会被其他组件共享。
为了定义原型范围的 bean,我们需要添加 @Scope 注释,指定我们想要的范围类型。
给出以下 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 定义,将其范围说明为原型:
@Configuration
public class PrototypeConfiguration {
@Bean
@Scope("prototype")
public MyBean prototypeBean() {
return new MyBean("prototype");
}
}
为了了解它是如何工作的,我们从 Spring 容器中检索 bean 并为其属性字段设置不同的值。接下来,我们将再次从容器中检索 bean 并查找其值:
MyBean prototypeBean1 = context.getBean("prototypeBean", MyBean.class);
prototypeBean1.setProperty("changed property");
MyBean prototypeBean2 = context.getBean("prototypeBean", MyBean.class);
logger.info("Prototype bean 1 property: " + prototypeBean1.getProperty());
logger.info("Prototype bean 2 property: " + prototypeBean2.getProperty());
查看以下结果,我们可以看到如何在每个 bean 请求上创建一个新实例:
Initializing prototype bean...
Initializing prototype bean...
Prototype bean 1 property: changed property
Prototype bean 2 property: prototype
一个常见的错误是假设每次调用或每个线程都重新创建 bean,但事实并非如此。而是创建 PER INJECTION(或从上下文中检索)实例。如果 Prototype 作用域 bean 只被注入一个单独的 bean,那么只有一个 Prototype 作用域 bean 的实例。
Spring 不管理原型 bean 的完整生命周期:容器实例化,配置,装饰和组装原型对象,将其交给客户端,然后不再了解该原型实例。