| 来源 | 说明 |
|---|---|
| sigleton | 默认 Spring Bean 作用域,一个 BeanFactory 有且仅有一个实例 |
| prototype | 原型作用域,每次依赖查找和依赖注入生成新 Bean 对象 |
| request | 将 Spring Bean 存储在 ServletRequest 上下文中 |
| session | 将 Spring Bean 存储在 HttpSession 中 |
| application | 将 Spring Bean 存储在 ServletContext 中 |
主要是 Singleton 和 Prototype 这两种,其余的是在后续版本中才加入的,并且在 BeanDefinition 中也只有 sigleton 和 prototype 两种作用域的定义
8.1 Singleton在一定范围内是唯一的,Spring 中就是在一个 BeanFactory 内部是唯一的
8.2 Prototype@Configuration
@PropertySource("default.properties")
public class BeanScopeDemo {
@Value("${usr.name:default}")
private String name;
@Value("${usr.age:28}")
private int age;
@Bean
public User singletonUser() {
return new User(this.name, this.age);
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public User prototypeUser() {
return new User(this.name, this.age);
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(BeanScopeDemo.class);
context.refresh();
System.out.println(context.getBean("singletonUser", User.class) == context.getBean("singletonUser", User.class));
System.out.println(context.getBean("prototypeUser", User.class) == context.getBean("prototypeUser", User.class));
context.close();
}
}
public class User implements BeanNameAware {
private transient String beanName;
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
@PostConstruct
public void init() {
System.out.println("用户 Bean[" + beanName + "]初始化...");
}
@PreDestroy
public void destroy() {
System.out.println("用户 Bean[" + beanName + "]销毁...");
}
@Override
public void setBeanName(String name) {
this.beanName = name;
}
}
// 运行结果:
用户 Bean[singletonUser]初始化...
true
用户 Bean[prototypeUser]初始化...
用户 Bean[prototypeUser]初始化...
false
用户 Bean[singletonUser]销毁...
Spring 容器没有办法管理 protoType Bean 完整的生命周期,也没有办法记录实例的存在。销毁回调方法将不会执行,可以利用 BeanPostProcessor 进行清扫工作。
结论:
-
Singleton Bean 无论依赖查找还是依赖注入,均为同一个对象,Prototype Bean 无论依赖查找还是依赖注入,均为新生成对象
-
如果依赖注入集合类型对象,Singleton Bean 和 Prototype Bean 均会存在一个且只有一个
-
无论是 Singleton 还是 Prototype Bean 均会执行初始化方法回调,不过仅 Singleton Bean 会执行销毁方法回调
配置
-
XML——
-
Java 注解——@RequestScope 或 @Scope(WebApplicationContext.SCOPE_REQUEST)
实现
-
API——RequestScope
对象会被代理,页面渲染时是新对象,通过 Model 传递给 JSP 的对象每次都是新的,但是代理对象是不变的
8.4 Session配置
-
XML——
-
Java 注解——@SessionScope 或 @Scope(WebApplicationContext.SCOPE_SESSION)
实现
-
API——SessionScope
对象会被代理,页面渲染时是新对象,通过 Model 传递给 JSP 的对象在每次会话中都是相同的,不同会话中不同,但是代理对象是不变的
8.5 Application配置
-
XML——
-
Java 注解——@ApplicationScope 或 @Scope(WebApplicationContext.SCOPE_APPLICATION)
实现
-
API——ServletContextScope
JSP EL 变量搜索路径 page -> request -> session -> application(ServletContext)
ApplicationContext 作用域其实就是将 Bean 放到 ServletContext 中进行存储,因此我们不必使用 Model 进行数据的传输,可以直接在 JSP 页面中使用 Application 作用域的bean
8.6 自定义 Bean 作用域-
实现 Scope
-
org.springfamework.beans.factory.config.Scope
-
-
注册 Scope
-
API——org.springframework.beans.factory.config.ConfigurableBeanFactory#registerScope
-
配置
-
8.7.1 Spring 内建的 Bean 作用域有几种?
六种:sigleton、prototype、request、session、application 以及 websocket
从设计模式:单例和原生(原型)
从web模式:request、session、application、websocket
8.7.2 singleton Bean 是否在一个应用中是唯一的
不是,只是在一个 BeanFactory 中是唯一的,整个应用可能包含多个应用上下文(层次上下文),不同上下文中互不影响
同样的,一个静态字段在 JVM 中是否唯一?不是唯一的,静态字段相对于 ClassLoader 唯一,但是一个 JVM 进程可能包含多个 ClassCloader
8.7.3 application 作用域 Bean 是否能被其他方案替代
是可以的,实际上,application bean 与 singleton bean 没有本质区别,无非是在某处进行了存储,跟 Ioc 容器中的 bean 是同一个



