Spring框架学习--浅谈@Scope注解

8 篇文章 0 订阅

在默认情况下,Spring应用上下文中所有bean都是作为以单例(singleton) 的形式创建的。也就是说,不管给定的一个bean被注入到其他bean多少次,每次所注入的都是同一个实例。在大多数情况下, 单例bean是理想的方案。 初始化和垃圾回收对象实例所带来的成本只留给一些小规模任务, 在这些任务中, 让对象保持无状态并且在应用中反复重用这些对象可能并不合理。有时候,所使用的类是易变的(mutable),它们会保持一些状态, 因此重用是不安全的。 在这种情况下,将class声明为单例的bean就不是什么好主意了, 因为对象会被污染, 稍后重用的时候会出现意想不到的问题。例如, 网上商城应用中, 可能会有一个bean代表用户的购物车。 如果购物车是单例的话, 那么将会导致所有的用户都会向同一个购物车中添加商品。

为解决这个问题,就必须了解一下Spring的作用域。Spring定义了多种作用域,可以基于这些作用域创建bean,包括:
单例(Singleton) : 在整个应用中, 只创建bean的一个实例。
原型(Prototype) : 每次注入或者通过Spring应用上下文获取的时候, 都会创建一个新的bean实例。
会话(Session) : 在Web应用中, 为每个会话创建一个bean实例。
请求(Rquest) : 在Web应用中, 为每个请求创建一个bean实例。
正如之前所述, Spring默认作用域都是单例的,但对于易变的类型, 这并不合适。如果选择其他的作用域, 要使用@Scope注解, 它可以与@Component或@Bean一起使用。

声明原型作用域
可以使用ConfigurableBeanFactory类的SCOPE_PROTOTYPE常量设置了原型作用域。也可以使用@Scope(“prototype”), 但是使用SCOPE_PROTOTYPE常量更加安全并且不易出错。因为编译器可以检查常量是否已经定义,而检查不了字符串是否正确。

1.在Java配置中将Notepad声明为原型bean,可以组合使用@Bean和@Scope来指定所需的作用域;
2.使用XML来配置bean的话, 可以使用<bean>元素的scope属性来设置作用。
不管使用哪种方式来声明原型作用域, 每次注入或从Spring应用上下文中检索该bean的时候, 都会创建新的实例。 这样所导致的结果就是每次操作都能得到自己想要的实例。

声明会话或请求作用域
回到购物车那个话题,如果购物车是原型作用域的, 那么在应用中某一个地方往购物车中添加商品, 在应用的另外一个地方可能就不可用了, 因为在这里注入的是另外一个原型作用域的购物车。而使用会话作用域,可能是最适合的解决方案,因为这与用户关联性最大。
要指定会话作用域, 依旧可以使用@Scope注解。需要将value设置成WebApplicationContext中的SCOPE_SESSION常量(它的值是session)。这会告诉Spring为Web应用中的每个会话创建一个ShoppingCart。这会创建多个ShoppingCart bean的实例,但是对于给定的会话只会创建一个实例, 在当前会话相关的操作中, 这个bean是相当于单例的。

需要注意的是,@Scope同时还有一个proxyMode属性, 这个属性解决了将会话或请求作用域的bean注入到单例bean中所遇到的问题。如果bean类型是具体类的话,必须将proxyMode属性设置为ScopedProxyMode.TARGET_CLASS, 以此来表明要以生成目标类扩展的方式创建代理。因为对于一个具体的类,Spring没有办法创建基于接口的代理了。
ScopedProxyMode.INTERFACES, 这表明这个代理要实现接口, 并将调用委托给实现bean。
这样做的原因是:Spring不会将实际的ShoppingCart bean注入到Service中,Spring会注入一个到bean的代理, 这个代理会暴露与ShoppingCart相同的方法, 所以Service会认为它就是一个购物车。 但是, 当Service调用ShoppingCart的方法时, 代理会对其进行懒解析并将调用委托给会话作用域内真正的ShoppingCart bean。请求作用域的bean应该也以作用域代理的方式进行注入。作用域代理能够延迟注入请求和会话作用域的bean。如下图所示。
这里写图片描述

使用XML来声明会话或请求作用域的bean, 就不能使用@Scope注解及其proxyMode属性了。 <bean>元素的scope属性能够设置bean的作用域, 要设置代理模式, 需要使用Spring aop命名空间的一个新元素:<aop:scoped-proxy>是与@Scope注解的proxyMode属性功能相同的Spring XML配置元素。 它会告诉Spring为bean创建一个作用域代理。 默认情况下, 它会使用CGLib创建目标类的代理。 但可以将proxy-target-class属性设置为false,进而要求它生成基于接口的代理。

request作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效,

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值