在大多数情况下,单例bean是很理想的方案。初始化和垃圾回收对象实例所带来的的成本只留给一些小规模任务,在这些任务中,让对象保持无状态并且在应用中反复重用这些对象可能并不合理。在这种情况下,将class声明为单例的bean会被污染,稍后重用的时候会出现意想不到的问题。

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

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

单例是默认的作用域,如果选择其他作用域,要使用@Scope注解,它可以与@Component或@Bean一起使用:

 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope; @Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Notepad{...}

当然也可以在@Bean下使用,参数可以直接写字符串prototype,singleton等,但并没有上述方式安全。

在xml模式中,可以在bean的属性中添加scope="prototype":

<bean id="notepad" class="..."  scope="prototype"/>

使用会话和请求作用域

使用会话作用域的bean最合适的莫过于购物车了,一个用户用一个购物车,而不是共用,或者因商品种类不同而创造无用的购物车。因为它与给定的用户关联性最大。示例如下:

 package soundSystem;

 import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext; @Component
@Scope(value=WebApplicationContext.SCOPE_SESSION,proxyMode=ScopedProxyMode.INTERFACES)
public class JDShoppingCart implements ShoppingCart{
public ShoppingCart getJDShoppingCart(){
return new JDShoppingCart();
}
}

这里,我们将value设置成了WebApplicationContext中的SCOPE_SESSION常量(它的值是session)。表明为Web应用中的每个会话创建一个ShoppingCart。这会创建多个ShoppingCart实例,但对于给定的会话,只创建一个实例。也就是说,在当前会话相关的操作中,ShoppingCart是单例的。

要注意的是,还有一个代理模式的属性,它被设置成ScopedProxyMode.INTERFACES。这个属性解决了讲会话或请求作用域的bean注入到单例bean中所遇到的问题。在描述proxyMode属性之前,我们先来看看proxyMode所解决问题的场景。假如要将ShoppingCart bean注入到单例StoreService bean的Setter方法中:

 package soundSystem;

 import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; @Component
public class StoreService {
private ShoppingCart shoppingCart; @Autowired
public void setShoppingCart(ShoppingCart shoppingCart) {
this.shoppingCart = shoppingCart;
}
}

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

另外,系统中将会有多个ShoppingCart实例:每个用户一个。我们并不想让Spring注入某个固定的ShoppingCart实例到StoreService中。我们希望的是当StoreService处理购物车功能时,它所使用的ShoppingCart实例恰好是当前会话所对应的那个。

所以Spring并不会将实际的ShoppingCart bean注入到StoreService中,Spring会注入到一个ShoppingCart bean的代理,这个代理会暴露与ShoppingCart相同的方法,所以StoreService会认为它是一个购物车。但是当StoreService调用ShoppingCart的方法时,代理会对其进行懒解析并将调用委托给会话作用域内真正的ShoppingCart bean。

现在,proxyMode被设置成ScopedProxyMode.INTERFACE常量,表明这个代理要实现ShoppingCart接口,并将调用委托给实现bean。如果需要实现类,则设置为ScopedProxyMode.TARGET_CLASS即可。

xml模式下配置代理模式

 <bean id="jDShoppingCart" class="soundSystem.JDShoppingCart" scope="session">
<aop:scoped-proxy/>
</bean>

也可以将proxy-target-class设置为false,从而要求它生成基于接口的代理:

         <bean id="jDShoppingCart" class="soundSystem.JDShoppingCart" scope="session">
<aop:scoped-proxy proxy-target-class="false"/>
</bean>

最新文章

  1. MUI跨域请求数据的例子:
  2. SharePoint 2013 Silverlight中使用Net客户端对象模型
  3. 网络方案 &amp; HTTP状态码
  4. 从零开始学Bootstrap(2)
  5. JSP out乱码
  6. Android SDK +Eclipse+ADT+CDT+NDK 开发环境在windows 7下的搭建
  7. POJ3691DNA repair
  8. 汉企C#面向对象——继承
  9. 使用Vagrant machine
  10. Android布局(一)layout_gravity 属性和 gravity属性的区别
  11. 转载:Raspberry Pi 树莓派入门
  12. Unity3D第三人称摄像机控制脚本
  13. [UE4]Spline Mesh Actor
  14. 精心收集的 48 个 JavaScript 代码片段,仅需 30 秒就可理解!
  15. ScrollView定时器复用
  16. Atitti 住房部建设指南
  17. Scipy
  18. Symbol 实现属性私有化的方式
  19. 理解JavaScript私有作用域
  20. ADO.net笔记

热门文章

  1. mac重装系统
  2. Nginx用户认证配置方法详解(域名/目录)
  3. cocos2d-x开发记录:一,搭建环境
  4. 在ModelSim中添加Xilinx仿真库
  5. [ci] jenkins的Timestamper插件-让日志显示时间
  6. 【Android】12.0 第12章 Intent及其过滤器&mdash;本章示例主界面
  7. js事件委托及其原理
  8. C#中通过Coded UI Test Web Page初体验(图文并茂,去繁就简!亲测通过哦~)
  9. Android的Message机制(简单小结)
  10. 在django中访问静态文件(js css img)