Spring系列8:bean的作用域
本文内容
- bean定义信息的意义
- 介绍6种bean的作用域
bean定义信息的意义
Spring中区分下类、类定义信息,类实例对象的概念?不容易理解,以餐馆中点炒饭为例。
类: 相当于你看到菜单上炒饭这个菜品,有这个菜。
类定义信息:相当于炒饭的烹饪法,烹饪法只有一份
类实例对象: 相当于按照上面烹饪法炒出来的一份炒饭,可以炒分多份出来。
Spring容器中创建了一个类定义信息的,就可以根据这个定义信息来创建个类实例对象出来,这个理解了很关键。Spring中不仅可以控制 bean 对象中的各种依赖项和配置值,还可以控制 bean 额作用范围。
介绍6种bean的作用域
Spring Framework 支持6个bean的作用域,其中4个仅在web类型的
ApplicationContext中可用。详细见下表
作用域 | 描述 |
---|---|
singleton | (默认)将单个 bean 定义限定为每个 Spring IoC 容器的单个对象实例。 |
prototype | 将单个 bean 定义限定为任意数量的对象实例 |
request | 将单个 bean 定义限定为单个 HTTP 请求的生命周期。也就是说,每个 HTTP 请求都有自己的 bean 实例,该实例是在单个 bean 定义的后面创建的。仅在web类型的 ApplicationContext有效。 |
session | 将单个 bean 定义限定为 HTTP 会话的生命周期。仅在web类型的 ApplicationContext有效。 |
application | 将单个 bean 定义限定为 ServletContext 的生命周期。仅在web类型的 ApplicationContext有效。 |
websocket | 将单个 bean 定义限定为 WebSocket 的生命周期。仅在web类型的 ApplicationContext有效。 |
从 Spring 3.0 开始,线程范围可用,但默认情况下未注册。
SimpleThreadScope感兴趣可以详细看下面自定义作用域。
singleton
只有一个单例 bean 的共享实例被管理,并且所有对具有与该 bean 定义匹配的一个或多个 ID 的 bean 的请求都会导致 Spring 容器返回一个特定的 bean 实例。"蝎子粑粑独一份"。注意是一个IoC容器内。
prototype
原型作用域下每次容器都会创建一个新的 bean 实例。通常来说,对有状态 bean适合使用原型,对无状态 bean适合使用单例。
下面的配置节指定了bean的作用域是原型的。
<bean id="accountService" class="x.y.z.AccountService" scope="prototype"/>
与其他范围相比,Spring 不管理原型 bean 的完整生命周期。容器实例化、配置和以其他方式组装原型对象并将其传递给客户端,由客户端去管理。bean生命周期后面介绍。
request, session, application, webSocket
这4个在web的应用上下文中使用的作用域,暂不展开讲,留给后面写spring mvc 专门讲。
自定义作用域和使用
如何自定义?
可以通过实现
org.springframework.beans.factory.config.Scope自定义作用域。
Scope接口有四种方法可以从作用域中获取对象,将它们从作用域中移除,并让它们被销毁。
package org.springframework.beans.factory.config; public interface Scope { // 从底层范围返回具有给定名称的对象 Object get(String name, ObjectFactory<?> objectFactory); // 从底层范围中删除具有给定的对象 Object remove(String name); // 注册要在作用域中指定对象的销毁时执行的回调 void registerDestructionCallback(String name, Runnable callback); // 省略 }
打铁要趁热,直接上
SimpleThreadScope的源码,解析下线程级别作用域是如何实现的。
package org.springframework.context.support; public class SimpleThreadScope implements Scope { private static final Log logger = LogFactory.getLog(SimpleThreadScope.class); // 1 bean是存放在ThreadLocal中的 绑定了当前线程 private final ThreadLocal<Map<String, Object>> threadScope = new NamedThreadLocal<Map<String, Object>>("SimpleThreadScope") { @Override protected Map<String, Object> initialValue() { return new HashMap<>(); } }; // 2 查ThreadLocal,有对应bean就直接返回,没有就创建一个放入ThreadLocal,在返回 @Override public Object get(String name, ObjectFactory<?> objectFactory) { Map<String, Object> scope = this.threadScope.get(); Object scopedObject = scope.get(name); if (scopedObject == null) { scopedObject = objectFactory.getObject(); scope.put(name, scopedObject); } return scopedObject; } // 3 从ThreadLocal中移除bean @Override @Nullable public Object remove(String name) { Map<String, Object> scope = this.threadScope.get(); return scope.remove(name); } // 4 销毁回调 @Override public void registerDestructionCallback(String name, Runnable callback) { logger.warn("SimpleThreadScope does not support destruction callbacks. " + "Consider using RequestScope in a web environment."); } @Override @Nullable public Object resolveContextualObject(String key) { return null; } @Override public String getConversationId() { return Thread.currentThread().getName(); } }
如何使用?
先将自定义的scope注入到容器中
编码的方式注册:
ConfigurableBeanFactory
接口提供了registerScope
来注册自定义的scope。Scope threadScope = new SimpleThreadScope(); beanFactory.registerScope("thread", threadScope);
配置文件方式的注册: 使用
CustomScopeConfigurer
以声明方式进行注册<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="thread"> <bean class="org.springframework.context.support.SimpleThreadScope"/> </entry> </map> </property> </bean> </beans>
bean配置中使用
使用方式普通的scope一样。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="thread"> <bean class="org.springframework.context.support.SimpleThreadScope"/> </entry> </map> </property> </bean> <bean id="thing2" class="x.y.Thing2" scope="thread"> <property name="name" value="Rick"/> <aop:scoped-proxy/> </bean> <bean id="thing1" class="x.y.Thing1"> <property name="thing2" ref="thing2"/> </bean> </beans>
总结
本文Spring中的7种作用域,以及如何自定义作用域并使用。下一篇介绍基于注解的Spring容器配置。
知识分享,转载请注明出处。学无先后,达者为先!
- Spring系列:第三篇-Spring容器三种实例化bean的方式以及Bean的作用域
- Spring中Bean的作用域—Spring官方文档系列
- spring2.5.6学习笔记六:配置Spring管理的bean的作用域
- Spring整理系列(11)——@Configuration注解、@Bean注解以及配置自动扫描、bean作用域 发表于2016/8/11 15:16:16 10628人阅读 分类: Spring
- Spring初学之bean之间的关系和bean的作用域
- SSH框架系列:Spring读取配置文件以及获取Spring注入的Bean
- spring中bean的作用域
- Spring中bean的作用域
- SSM框架搭建系列(一)-- Error creating bean with name 'org.springframework.cache.interceptor.CacheInterceptor
- Spring整理系列(01)——spring概念简介、bean扫描与注册实现方式
- 配置Spring管理的bean的作用域
- Spring 自学系列之IOC-4 【bean的标识id VS name】
- Spring3之Bean的作用域
- Spring管理的bean的作用域
- 【Spring3.0系列】---Bean不同配置方式比较 和适用场合
- Spring中Bean获取方式,实例化对象的方式,Bean的作用域示例
- 详解Spring中bean的作用域
- Spring之Bean的作用域与生命周期
- 读懂Spring核心系列1(注册与获取bean)
- Spring注解@Scope-设置组件作用域及bean的创建时间