Spring Bean 作用域
来源 | 说明 | 目的 |
---|---|---|
singleton | 默认 Spring Bean 作用域,一个 BeanFactory 有且仅有一个实例 | |
prototype | 原型作用域,每次依赖查找和注入生成新的 Bean 对象 | |
request | 将 Spring Bean 存储在 ServletRequest 上下文中 | 给模板引擎用的 |
session | 将 Spring Bean 存储在 HttpSession 中 | 给模板引擎用的 |
application | 将 Spring Bean 存储在 ServletContext 中 | 给模板引擎用的 |
补充知识:
JSP 四大作用域:当前页面、当前请求、当前会话,当前应用(JSP 四大作用域详解)
singleton & prototype Bean 作用域
BeanDefinition 中有 isSingleton 和 isPrototype 的判断,
结论
结论一:
- Singleton Bean 无论依赖查找还是依赖注入,均为同一个对象
- Prototype Bean 无论依赖查找还是依赖注入,均为新生成的对象
结论二:
- 如果依赖注入集合类型的对象,Singleton Bean 和 Prototype Bean 均会存在一个
- Prototype Bean 有别于其他地方的依赖注入 Prototype Bean
结论三:
- 无论是 Singleton 还是 Prototype Bean 均会执行初始化方法回调
- 不过仅 Singleton Bean 会执行销毁方法回调(Singleton Bean 是一对一; Prototype Bean 相当于 bean 和对象的关系一对多,容器没法映射)
- 但是 Prototype Bean 可以手动销毁
相关代码
BeanScopeDemo.class
/**
* Bean 作用域示例
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class BeanScopeDemo implements DisposableBean {
// 结论一:
// Singleton Bean 无论依赖查找还是依赖注入,均为同一个对象
// Prototype Bean 无论依赖查找还是依赖注入,均为新生成的对象
// 结论二:
// 如果依赖注入集合类型的对象,Singleton Bean 和 Prototype Bean 均会存在一个
// Prototype Bean 有别于其他地方的依赖注入 Prototype Bean
// 结论三:
// 无论是 Singleton 还是 Prototype Bean 均会执行初始化方法回调
// 不过仅 Singleton Bean 会执行销毁方法回调
@Bean
// 默认 scope 为 singleton
public static UserForBeanScope singletonUser() {
return createUser();
}
@Bean
@Scope(ConfigurableListableBeanFactory.SCOPE_PROTOTYPE)
public static UserForBeanScope prototypeUser() {
return createUser();
}
@Autowired
@Qualifier("singletonUser")
public UserForBeanScope singletonUser;
@Autowired
@Qualifier("singletonUser")
public UserForBeanScope singletonUser1;
@Autowired
@Qualifier("singletonUser")
public UserForBeanScope prototypeUser;
@Autowired
@Qualifier("prototypeUser")
public UserForBeanScope prototypeUser1;
@Autowired
@Qualifier("prototypeUser")
public UserForBeanScope prototypeUser2;
@Autowired
private Map<String, UserForBeanScope> users;
@Autowired
private ConfigurableListableBeanFactory beanFactory;// Resolvable Dependency
private static UserForBeanScope createUser() {
UserForBeanScope userForBeanScope = new UserForBeanScope();
userForBeanScope.setId(System.nanoTime());
return userForBeanScope;
}
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 配置类(配置类也是 Spring 的 Bean)
applicationContext.register(BeanScopeDemo.class);
// 销毁方式一,不建议使用,因为回调是要将 bean 对象返回
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();
// 结论一与结论二演示
scopedBeanByLookUp(applicationContext);
scopedBeanByInject(applicationContext);
// 关闭 Spring 应用上下文
applicationContext.close();
}
/**
* 依赖查找
*
* @param applicationContext 应用程序上下文
*/
private static void scopedBeanByLookUp(AnnotationConfigApplicationContext applicationContext) {
for (int i = 0; i < 3; i++) {
UserForBeanScope singletonUser = applicationContext.getBean("singletonUser", UserForBeanScope.class);
System.out.println("singletonUser = " + singletonUser);
UserForBeanScope prototypeUser = applicationContext.getBean("prototypeUser", UserForBeanScope.class);
System.out.println("prototypeUser = " + prototypeUser);
}
}
private static void scopedBeanByInject(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);
}
// 销毁方式二:实现 DisposableBean 接口,重写 destroy 方法进行销毁
@Override
public void destroy() throws Exception {
System.out.println("当前 BeanScopeDemo 中的 Prototype Bean 正在销毁中...");
this.prototypeUser.destory();
this.prototypeUser1.destory();
this.prototypeUser2.destory();
// 获取 BeanDefinition
for (Map.Entry<String, UserForBeanScope> entry : this.users.entrySet()) {
String beanName = entry.getKey();
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
if (beanDefinition.isPrototype()) { // 如果当前 Bean 是 prototype scope
UserForBeanScope userForBeanScope = entry.getValue();
userForBeanScope.destory();
}
}
System.out.println("当前 BeanScopeDemo 中的 Prototype Bean 销毁完成");
}
}
User.Class
/**
* 用户
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class UserForBeanScope implements BeanNameAware {
// 通过实现 BeanNameAware 接口对 bean 名称修改
private Long id;
private String name;
/**
* 当前 Bean 的名称
*/
private transient String beanName;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
// 结论三演示
@PostConstruct
public void init() {
System.out.println("User Bean [" + beanName + "] 初始化……");
}
@PreDestroy
public void destory() {
System.out.println("User Bean [" + beanName + "] 销毁……");
}
@Override
public void setBeanName(String name) {
this.beanName = name;
}
}
request & session Bean 作用域
request:前端每次请求是一个新的对象,创建新生成对象用的对象是同一个经过 CGLIB 增强的对象
session:每次会话是一个新的对象,创建新生成对象用的对象是同一个经过 CGLIB 增强的对象
application Bean 作用域
个人学下来感觉就是为了方便直接获取,作用类似单例。未深究
自定义 Bean 作用域
先实现 Scope 接口
org.springframework.beans.factory.config.Scope
后注册
- API:org.springframework.beans.factory.config.ConfigurableBeanFactory#registerScope
- 配置:
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="...">
</entry>
</map>
</property>
</bean>
相关代码