Spring in Action 4 读书笔记之如何定义 bean 的使用范围

字数959 大约花费4分钟

目录

  1. 1. bean 的使用范围
  2. 2. 使用 request 或 session 范围

Spring in Action(Spring 实战)的第三章第四节(3.4 Scoping beans)讲述了 bean 的使用范围。在不同场景下,可以使用不同的使用范围,比如 web 程序一般使用和普通应用程序不同的范围。

bean 的使用范围

默认情况下,Spring 应用上下文中的 bean 都是单例。这意味着无论一个 bean 被注入多少次,总是注入同一个实例。

有时候,要处理互斥的任务,要求 bean 的属性值只被其中一个任务访问和修改,这时候,单例会引起问题。别担心,除了单例外,Spring 还定义了 bean 的其它使用范围。Spring 定义的 bean 使用范围如下:

  • Singleton:单例,整个应用程序使用唯一实例。
  • Prototype:每次注入时都会从 Spring 应用上下文中创建一个新的实例。
  • Session:在 web 应用中,为每个 session 创建一个实例。
  • Request:在 web 应用中,为每个 request 创建一个实例。

可以使用 @Scope 标签标注 @Component 标签(定义准备被自动注入的 bean),也可以使用 @Scope 标签标注 @Bean 标签(显式定义 bean)。

在 xml 中,也可以使用 bean 标签的 scope 属性指定 bean 的范围。

使用自动注入的例子:

1
2
3
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Notepad { ... }

使用 java 显式定义 bean 的例子:

1
2
3
4
5
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Notepad notepad() {
return new Notepad();
}

使用 xml 中 bean 标签的 scope 属性显示定义 bean 的例子:

1
2
3
<bean id="notepad"
class="com.myapp.Notepad"
scope="prototype" />

上面的这些例子,都会在每次注入时从 Spring 应用上下文中创建一个新的实例。

使用 request 或 session 范围

在 web 应用中,在 request 或 session 范围内共享一个 bean 会非常有用。比如在电子商务应用中的购物车,如果定义为 Singleton,所有的用户就会使用同一个购物车,显然会造成混乱。如果定义为 Prototype,那么每次注入的都是一个新的购物车,那么这个购物车就没法保存东西了。应该定义 session 范围的 bean:

1
2
3
4
5
@Component
@Scope(
value=WebApplicationContext.SCOPE_SESSION,
proxyMode=ScopedProxyMode.INTERFACES)
public ShoppingCart cart() { ... }

value 属性定义了这个 bean 的使用范围是 session。另一个 proxyMode 是为了解决使用 session 或 request 范围的 bean 造成的问题。来看看没有定义这个属性会有什么问题,先看下面注入这个 bean 的例子:

1
2
3
4
5
6
7
@Component
public class StoreService {
@Autowired
public void setShoppingCart(ShoppingCart shoppingCart) {
this.shoppingCart = shoppingCart;
}
}

StoreService 本身是一个单例的 bean(没有使用 @Scope,使用默认范围),而 shoppingCart 是一个 session 范围的 bean。这样会带来两个问题。首先,单例的 bean 在 Spring 应用上下文加载时就会创建,而这个时候 session 范围的 bean 还没有创建,session 范围的 bean 要等到该用户到来,生成了相应 session 时,才会创建。第二个问题是,单例的 bean 只有一个实例,而 session 范围的 bean 取决于 session 的个数,一般有多个实例,这样,没有办法知道要为 StoreService 注入哪个 shoppingCart 实例。

Spring 对 scope 范围的 bean 进行代理

所以,需要使用代理模式,如图,为 shoppingCart 创建一个代理,这个代理定义了 ShoppingCart 的所有方法,在注入 bean 时,不是直接注入 shoppingCart 实例,而是注入这个代理。由于 ShoppingCart 是一个接口,所以这里使用 ScopedProxyMode.INTERFACES。如果是具体实例,则改用 ScopedProxyMode.TARGET_CLASS。

request 范围的 bean 的用法和 session 范围的 bean 类似,这里不再赘述。

谈谈 IT的文章均为原创或翻译(翻译会注明外文来源),转载请以链接形式标明本文地址: http://tantanit.com/springinaction4-du-shu-bi-ji-zhi-ru-he-ding-yi-bean-de-shi-yong-fan-wei/

谈谈IT

欢迎关注官方微信公众号获取最新原创文章