bean的作用域

Spring作用域定义

默认情况下,Spring应用上下文中的bean都是以单例(singleton)的形式创建的。

Spring定义了多种作用域,可以基于这些作用域创建bean:

  • 单例(Singleton):在整个应用中,只创建bean一个实例。
  • 原型(Prototype):在每次注入或Spring应用上下文获取的时候,都会创建一个新的bean实例。
  • 会话(Session):在Web应用中,为每个会话创建一个bean实例。
  • 请求(Request):在Web应用中,为每个请求创建一个bean实例。

1.组件扫描的方式

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

2.Java配置的方式

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

3.XML配置的方式

1
<bean id="notePad" class="com.ql.NotePad" scope="prototype"/>

使用会话和请求作用域

在Web应用中,如果能够实例化会话和请求范围内共享的bean,将是非常有价值的事情。如在电子商务应用中,可能用一个bean代表购物车。如果该bean是单例,就会导致导致所有用户都会向同一个购物车添加商品。如果购物车是原型作用域,那么在应用中某个地方向购物车添加商品,在应用的另一个地方可能就用不了。

就购物车的bean来说,会话作用域是最合适的:

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

@Scopevalue设置成session。另一个属性proxyMode设置为ScopedProxyMode.INTERFACES,这个属性解决了将会话或请求作用域的bean注入到单例bean中所出现的问题。以下是该属性解决的问题场景。

假如要把ShoppingCartbean注入到StoreService单例bean的set方法中,如下:

1
2
3
4
5
6
7
8
9
@Component
public class StoreService {

private ShoppingCart shoppingCart;

public void setShoppingCart(ShoppingCart shoppingCart) {
this.shoppingCart = shoppingCart;
}
}

因为StoreService是一个单例的bean,会在Spring应用上下文加载的时候创建。当它创建的时候,Spring会视图将ShoppingCartbean注入到set方法中。但是ShoppingCartbean是会话作用域,此时并不存在。知道某个用户进入系统,创建会话之后,才会出现ShoppingCart实例。

另外,多个会话产生多个ShoppingCart实例,我们希望StoreService使用的ShoppingCart实例是当前会话的。

Spring并不会将实际的ShoppingCartbean注入到StoreService中,Spring会注入一个到ShoppingCartbean的代理,如下图。这个代理会暴露与ShoppingCart相同的 的方法,当StoreService调用ShoppingCart的方法时,代理会对其进行懒解析并将调用委托给会话作用域内真正ShoppingCartbean。

会话作用域代理


以上

LeoQin wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
0%