Spring定义了多种作用域,我们在使用的时候可以根据使用的需求来选择对应的作用域,这些作用域,包括(第二个括号中为更安全的注解方法,具体更多参数可查看接口代码)

  • 单例(Singleton)(ConfigurableBeanFactory.SCOPE_SINGLETON):在整个应用中,只创建bean的一个实例。
  • 原型(Prototype)(ConfigurableBeanFactory.SCOPE_PROTOTYPE):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。
  • 会话(Session)(WebApplicationContext.SCOPE_SESSION):在Web应用中,为每个会话创建一个bean实例。
  • 请求(Rquest)(WebApplicationContext.SCOPE_REQUEST):在Web应用中,为每个请求创建一个bean实例。

单例是默认的作用域,但是正如之前所述,对于易变的类型,这并不合适。如果选择其他的作用域,要使用@Scope注解,它可以与@Component或@Bean一起使用。

我们可以分别使用三种配置Bean的方法来指定Bean的作用域。

使用隐式的组件扫描方式:

@Component
@Scope("prototype")
//@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class DangNianQing implements CompactDisc {
}
}

使用java方式配置

    @Bean
@Scope("prototype")
public CDPlay cdPlay(CompactDisc compactDisc){
return new CDPlay(compactDisc);
}

使用xml方式配置

    <bean id="dangNianQing" class="com.bean.xml.DangNianQing" scope="prototype"/>

假如我们现在正在做一个购物的网站,就购物车这个Bean来说,如果没有指定他的作用于的话,那么就是默认的单例模式,那么就会发生:所有的用户都会向同一个购物车中添加商品。另一方面,如果购物车是原型作用域的,那么在应用中某一个地方往购物车中添加商品,在应用的另外一个地方可能就不可用了,因为在这里注入的是另外一个原型作用域的购物车。所以这个时候,最适合的就是用会话作用域。

使用的方法是:

    @Component
@Scope(value = WebApplicationContext.SCOPE_SESSION,
proxyMode = ScopedProxyMode.INTERFACES)
public ShoppingCar cart(){ }

正好有个Service,有个Setter方法需要注入Bean

@Component
public class storeService{
@Autowired
public void setShoppingCar(ShoppingCar shoppingCar){
this.shoppingCar = shoppingCar;
}
}

从上面的代码中我们可以看出storeService是默认的 为单例Bean,会在Spring应用上下文加载的时候创建,当然在创建的时候也会企图去将ShoppingCar注入进来,但是ShoppingCart bean是会话作用域的,此时并不存在。直到某个用户进入系统,创建了会话之后,才会出现ShoppingCart实例。另外,系统中将会有多个ShoppingCart实例:每个用户一个。我们并不想让Spring注入某个固定的ShoppingCart实例到StoreService中。我们希望的是当StoreService处理购物车功能时,它所使用的ShoppingCart实例恰好是当前会话所对应的那一个。

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

现在,我们带着对这个作用域的理解,讨论一下proxyMode属性。如配置所示,proxyMode属性被设置成了copedProxyMode.INTERFACES,这表明这个代理要实现ShoppingCart接口,并将调用委托给实现bean。

如果ShoppingCart是接口而不是类的话,这是可以的(也是最为理想的代理模式)。但如果ShoppingCart是一个具体的类的话,Spring就没有办法创建基于接口的代理了。此时,它必须使用CGLib来生成基于类的代理。所以,如果bean类型是具体类的话,我们必须要将proxyMode属性设置为ScopedProxyMode.TARGET_CLASS,以此来表明要以生成目标类扩展的方式创建代理。

下面也学习下在xml中配置作用域的代理

<bean id="dangNianQing" class="com.bean.xml.DangNianQing" scope="session">
<aop:scoped-proxy></aop:scoped-proxy>
</bean>

其中的<aop:scoped-proxy>与@Scope中的proxyMode 一样的,因为Bean类型是类 不是接口所以要把 proxy-target-class属性设置为false

<bean id="dangNianQing" class="com.bean.xml.DangNianQing" scope="session">
<aop:scoped-proxy proxy-target-class="false" />
</bean>

总的来说:就是如果我们有一个接口或者类 需要注入Bean的时候,我们可以委托给代理,这样就每次请求会话的时候,都有一个与其对应的Bean了

以上就是Bean作用域相关的知识,如果有错误,请指出,谢谢

最新文章

  1. sysv-rc-conf管理Ubuntu server开机启动服务
  2. 前端代码目录结构、常用 piugin、元素补充用法及其它注意事项
  3. ORB-SLAM(一)简介
  4. Optimizely:在线网站A/B测试平台
  5. pytessact 出现Error2错误
  6. VPS折腾
  7. jQuery学习实用记录
  8. C++ 常用术语(后续补充)
  9. linux runlevel
  10. Matlab命令系列之目录操作
  11. IOS UINavigationController 操作相关集合
  12. MySQL 5.7 启用查询日志
  13. Android 内核初识(7)RefBase、LightRefBase、sp和wp
  14. [MSSQL]从SQL语句的角度 提高数据库的访问性能
  15. werkzeug中reloader的实现
  16. [附录]Discuz X2.5 模板目录结构注释说明
  17. 快速搭建vsftp 服务器并配置指定目录
  18. ListView 无 DataSource 依然用 DataPager 翻页
  19. 初次面对c++
  20. VUE项目快速构建

热门文章

  1. iOS开发之NSUserDefaults
  2. Python学习示例源码
  3. FFmpeg 入门(3):播放音频
  4. 使用C++11实现一个半同步半异步线程池
  5. nginx结合fastcgi
  6. TCP深入详解
  7. 学Git,用Git ③
  8. 深度学习笔记(一):logistic分类【转】
  9. [转载]Javassist 使用指南(一)
  10. vue编译环境和线上环境url切换