目录
一、背景
在默认情况下,Spring 上下文中所有的 bean 都是以单例的形式创建。但是在一些场景中,会发现一个 bean 是可能带有状态的,因此重用并不安全。或者是某些场景下,希望 bean 能带有某些不同的值,如会话中不同用户的信息。这时候就需要控制 bean 的作用域了。
二、分类
Spring 中定义了 bean 有以下几个作用域:
- 单例(singleton):整个上下文中,每个 bean 只会有一个实例。
- 原型(prototype):每次从上下文获取的都会创建一个新的 bean 实例。
- 请求(request):在 Web 应用中,为每个请求创建一个 bean 实例。
- 会话(session):在 Web 应用中,为每个会话创建一个 bean 实例。
- 全局会话(globalSession):用于 Porlet,同一个全局 Session 共享一个 bean, 仅用于 WebApplication 环境。
三、控制方式
1.自动装配和 JavaConfig 的场景
我们通过在使用 @Component 或 @Bean 时添加 @Scope 注解来设置其作用域。
例如:
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class People() { ... }
@Component
@Scope(
value=WebApplicationContext.SCOPE_SESSION,
proxyMode=ScopedProxyMode.INTERFACES)
public class Person() { ... }
其中,ConfigurableBeanFactory.SCOPE_PROTOTYPE 的值即为 "prototype" ,我们使用常量不叫不容易拼写错误。
2.XML配置的场景
我们通过 <bean> 元素的 scope 属性来设置作用域:
<bean id="people"
class="aa.bb.People"
scope="prototype" />
<bean id="people"
class="aa.bb.People"
scope="session" >
<aop:scoped-proxy proxy-targert-class="false">
</bean>
3.在非 web 环境中注入 web 环境的 bean
在上面的例子中我们可以看到,在 web 作用域中的类型(request、session 和 globalSession)在定义时还会加上一个作用域代理,因为web 类型的作用域是在会话发生时上下文才会进行创建 bean,而非 web 类型作用域的 bean 在一开始便进行创建,此时会发生装配的问题。
于是我们为wed 作用域类型的 bean 创建一个代理类,该代理类暴露出于实际类相同的方法,先将此代理类注入到非web类型的 bean 中,当会话发生时,动态代理会判断实际类处于哪个线程,并进行实际的调用。
因为 Java 语言只支持对接口的动态代理,如果要对类进行动态代理,需要加入 CGLib 库。代理类型也不同,分别为:
自动装配 和 JavaConfig 风格配置:
- 接口类型:proxyMode=ScopedProxyMode.INTERFACES
- 类类型:proxyMode=ScopedProxyMode.TARGET_CLASS
XML 风格配置:
- 接口类型:<aop:scoped-proxy proxy-targert-class="false">
- 类类型:<aop:scoped-proxy >
(原创不易,转载请注明出处!!)