第八章:Spring Bean作用域(Scopes)
Spring Bean 作用域
来源 | 说明 |
---|---|
singleton | 默认 Spring Bean 作用域,一个 BeanFactory 有且仅有一个实例 |
prototype | 原型作用域,每次一来查找和依赖注入时生成新的 bean 对象 |
request | 将 Spring Bean 存储在 ServletRequest 上下文中 |
session | 将 Spring Bean 存储在 HttpSession 中 |
application | 将 Spring Bean 存储在 ServletContext 中 |
singleton Bean 作用域
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
// ...
/**
* Override the target scope of this bean, specifying a new scope name.
* @see #SCOPE_SINGLETON
* @see #SCOPE_PROTOTYPE
*/
void setScope(@Nullable String scope);
/**
* Return the name of the current target scope for this bean,
* or {@code null} if not known yet.
*/
@Nullable
String getScope();
// Read-only attributes
// ...
/**
* Return whether this a <b>Singleton</b>, with a single, shared instance
* returned on all calls.
* @see #SCOPE_SINGLETON
*/
boolean isSingleton();
/**
* Return whether this a <b>Prototype</b>, with an independent instance
* returned for each call.
* @since 3.0
* @see #SCOPE_PROTOTYPE
*/
boolean isPrototype();
// ...
}
prototype Bean 作用域
public class User implements BeanNameAware {
private Long id;
/**
* 当前 Bean 的名称
*/
private transient String beanName;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@PostConstruct
public void init() {
System.out.println("User Bean [" + beanName + "] 初始化...");
}
@PreDestroy
public void destroy() {
System.out.println("User Bean [" + beanName + "] 销毁中...");
}
@Override
public void setBeanName(String name) {
this.beanName = name;
}
}
public class BeanScopeDemo implements DisposableBean {
@Bean
// 默认 scope 就是 "singleton"
public static User singletonUser() {
return createUser();
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public static User prototypeUser() {
return createUser();
}
private static User createUser() {
User user = new User();
user.setId(System.nanoTime());
return user;
}
@Autowired
@Qualifier("singletonUser")
private User singletonUser;
@Autowired
@Qualifier("singletonUser")
private User singletonUser1;
@Autowired
@Qualifier("prototypeUser")
private User prototypeUser;
@Autowired
@Qualifier("prototypeUser")
private User prototypeUser1;
@Autowired
@Qualifier("prototypeUser")
private User prototypeUser2;
@Autowired
private Map<String, User> users;
@Autowired
private ConfigurableListableBeanFactory beanFactory; // Resolvable Dependency
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 Configuration Class(配置类) -> Spring Bean
applicationContext.register(BeanScopeDemo.class);
applicationContext.addBeanFactoryPostProcessor(beanFactory -> {
beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.printf("%s Bean 名称:%s 在初始化后回调...%n", bean.getClass().getName(), beanName);
return bean;
}
});
});
// 启动 Spring 应用上下文
applicationContext.refresh();
// 结论一:
// Singleton Bean 无论依赖查找还是依赖注入,均为同一个对象
// Prototype Bean 无论依赖查找还是依赖注入,均为新生成的对象
// 结论二:
// 如果依赖注入集合类型的对象,Singleton Bean 和 Prototype Bean 均会存在一个
// Prototype Bean 有别于其他地方的依赖注入 Prototype Bean
// 结论三:
// 无论是 Singleton 还是 Prototype Bean 均会执行初始化方法回调
// 不过仅 Singleton Bean 会执行销毁方法回调
scopedBeansByLookup(applicationContext);
scopedBeansByInjection(applicationContext);
// 显示地关闭 Spring 应用上下文
applicationContext.close();
}
private static void scopedBeansByLookup(AnnotationConfigApplicationContext applicationContext) {
for (int i = 0; i < 3; i++) {
// singletonUser 是共享 Bean 对象
User singletonUser = applicationContext.getBean("singletonUser", User.class);
System.out.println("singletonUser = " + singletonUser);
// prototypeUser 是每次依赖查找均生成了新的 Bean 对象
User prototypeUser = applicationContext.getBean("prototypeUser", User.class);
System.out.println("prototypeUser = " + prototypeUser);
}
}
private static void scopedBeansByInjection(AnnotationConfigApplicationContext applicationContext) {
BeanScopeDemo beanScopeDemo = applicationContext.getBean(BeanScopeDemo.class);
System.out.println("beanScopeDemo.singletonUser = " + beanScopeDemo.singletonUser);
System.out.println("beanScopeDemo.singletonUser1 = " + beanScopeDemo.singletonUser1);
System.out.println("beanScopeDemo.prototypeUser = " + beanScopeDemo.prototypeUser);
System.out.println("beanScopeDemo.prototypeUser1 = " + beanScopeDemo.prototypeUser1);
System.out.println("beanScopeDemo.prototypeUser2 = " + beanScopeDemo.prototypeUser2);
System.out.println("beanScopeDemo.users = " + beanScopeDemo.users);
}
@Override
public void destroy() throws Exception {
System.out.println("当前 BeanScopeDemo Bean 正在销毁中...");
this.prototypeUser.destroy();
this.prototypeUser1.destroy();
this.prototypeUser2.destroy();
// 获取 BeanDefinition
for (Map.Entry<String, User> entry : this.users.entrySet()) {
String beanName = entry.getKey();
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
if (beanDefinition.isPrototype()) { // 如果当前 Bean 是 prototype scope
User user = entry.getValue();
user.destroy();
}
}
System.out.println("当前 BeanScopeDemo Bean 销毁完成");
}
}
- 注意事项
- Spring 容器没有办法管理 prototype Bean 的完整生命周期,也没有办法记录实例的存在。销毁回调方法将不会执行,可以使用 BeanPostProcessor 进行清扫工作(有一定的局限性)。
request Bean 作用域
- 配置
- XML :
- Java 注解
- @RequestScope
- @Scope(WebApplicationContext.SCOPE_REQUEST)
- 实现
- API : RequestScope
web 环境:xxx
session Bean 作用域
- 配置
- XML :
- Java 注解
- @SessionScope
- @Scope(
WebApplicationContext.SCOPE_SESSION
)
- 实现
- API :
SessionScope
- API :