已知spring 3+已拥有多种不同的作用域: singleton(默认)、prototype、request、session、global session。(参考: spring中scope作用域(转))

到目前为止,其实还没在项目中实际遇到要修改作用域的情况。

但却知道有大概类似这么一种说法: spring的bean中不允许(或不建议)定义成员变量,不管是public还是private。

但之前在做一个功能的时候确实遇到了想在service定义一个成员变量Map类型的,但有映像spring中默认是单例,结合单例的特性。考虑到可能定义成员变量有问题,所以就重新回来看一下。

(最后也没采用定义成员变量的方式,还是用的参数传递。)

一、测试singleton、prototype的差异

1.1 singleton主要测试代码
@Controller
@Scope("singleton")
public class SingletonController {@Autowiredprivate SingletonService singletonService;private Integer controllerIndex = 1;@RequestMapping("/singleton")@ResponseBodypublic Map<String, Object> singleton(){Map<String, Object> rs = new HashMap<>();rs.put("service_index",singletonService.getIndex());rs.put("controller_index",controllerIndex);rs.put("controller_hashCode",this.hashCode());rs.put("service_hashCode",singletonService.hashCode());rs.put("cache",singletonService.getCache());return rs;}
}

@Service
@Scope("singleton")
public class SingletonService {private Map<String,Object> cache = new HashMap<>();private Integer index = 1;public Map<String, Object> getCache() {return cache;}public Integer getIndex() {cache.put("index-"+index,index);return index++;}
}

结果猜想:

1) 每次请求后controller_index、service_index都在递增。

2) controller_hashCode、service_hashCode每次都保持不变,因为单例只有一个实例。(java中得不到内存地址,变相的hashCode在一定情况下可以表示内存)

3) cache的key/value一直在增多,请求一次多一个。

这些全部都符合单例的特性。

1.2 prototype主要测试代码
@Controller
@Scope("prototype")
public class PrototypeController {@Autowiredprivate PrototypeService prototypeService;private Integer controllerIndex = 1;@RequestMapping("/prototype")@ResponseBodypublic Map<String, Object> singleton(){Map<String, Object> rs = new HashMap<>();rs.put("service_index",prototypeService.getIndex());rs.put("controller_index",controllerIndex);rs.put("controller_hashCode",this.hashCode());rs.put("service_hashCode",prototypeService.hashCode());rs.put("cache",prototypeService.getCache());return rs;}
}

@Service
@Scope("prototype")
public class PrototypeService {private Map<String,Object> cache = new HashMap<>();private Integer index = 1;public Map<String, Object> getCache() {return cache;}public Integer getIndex() {cache.put("index-"+index,index);return index++;}
}

结果猜想:

1) controller_index、service_index始终都是1。

2) controller_hashCode、service_hashCode每次都在改变。

3) cache只有一个key/value,即{"index-1": 1}。

1.3 结论

实际的结果和猜想完全符合,就是简单的单例/多例的区别。

所以如果存在类似的代码:

想现在aMethod()中处理一些逻辑,然后把符合的保存起来供bMethod()使用。并且你简单的测试不会有问题,因为是单线程的测试。

但现在整体来看,如果多个用户同时操作。本来A是put(1,"a"),但是此时B又紧接着put(1,"b")。A先进入bMethod(),那么get(1) = "b",这就是明显的多线程并发问题。

当然可以把Scope改成prototype,但现在的处境是: 1) 没绝对的比较。2) 整个项目中并没有用prototype的先例。

所以最常见的作法是改成方法传参:

@Service
@Scope("singleton")
public class SingletonService {public void aMethod() {private Map<String,Object> cache = new HashMap<>();// 一些逻辑cache.put(...);bMethod();}public void bMethod(Map<String,Object> cache) {Object obj = cache.get(...);// 一些逻辑}
}

二、此文的真正目的

简单目的: 在spring默认情况下的bean中定义成员变量带来的风险。

但,其实是记录spring是怎么解决线程安全的。(详见: Spring单例与线程安全小结)

我个人对线程也不是足够了解,去零零碎碎看过,但实际项目中确实还没完全真正的结果过。

但在以前看过过一篇文章(就是上面那篇),写spring是怎么解决线程安全的,写spring利用的不是线程同步机制(synchronized)而是用的ThreadLocal。

这只记录下两者的差异,主要还是上面那篇博客中说的。

synchronized: 时间换空间,以较慢的执行时间来节约空间的被占用。

在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。

ThreadLocal: 空间换时间,占用更多的空间来换取较快的执行时间。

在ThreadLocal中,会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。

ps: 最近很长一段时间一直相当烦躁,此文章本来很简单,但写到最后我自己都不知道自己到底想表达什么、想记录什么....感觉更像应付式的给自己一个任务,形式一般的写一篇文章....

转载于:https://www.cnblogs.com/VergiLyn/p/6965571.html

【Spring】bean的作用域(@Scope) - singleton、prototype相关推荐

  1. spring之bean的作用域scope的值的详解

    今天研究了一下scope的作用域.默认是单例模式,即 scope="singleton".另外scope还有prototype.request.session.global ses ...

  2. spring bean的作用域和生命周期

    一.spring bean的作用域 五种作用域:singleton.prototype.request.session.globalSession request.session和global ses ...

  3. Spring -Bean的作用域

    在 Spring 中, 可以在 <bean> 元素的 scope 属性里设置 Bean 的作用域. 默认情况下 bean 是单例的 但有的时候, bean 就不能使单例的. 例如: Str ...

  4. Bean的作用域scope

    Bean的作用域scope 1.singleton 单例,指一个bean容器中只存在一份 2.prototype 每次请求(每次使用)创建新的实例,destroy方式不生效 3.request 每次h ...

  5. Spring Bean的作用域之prototype

    Spring中Bean的默认最用域是单例,即singleton prototype是只在每次getBean的时候都去重新创建一个对象.下面我们来掩饰一下这种场景 使用SpringBoot项目.创建两个 ...

  6. spring bean的使用范围:singleton,prototype,request,session,application

    singleton prototype bean的学习 /** 结论一:singleton bean 只有一个:prototype bean每次都会创建新的 结论二:对于集合对象,会有两个user对象 ...

  7. Spring Bean的作用域及生命周期

    Bean的作用域 在bean声明时它有一个scope属性,它是用于描述bean的作用域. 可取值有: singleton:单例 代表在spring ioc容器中只有一个Bean实例 (默认的scope ...

  8. Spring Bean的作用域(作用范围)

    文章目录 scope 1. 注解方式配置1.1 测试singleton1.2 测试prototype 2. XML方式配置 在Spring中使用 scope来表示一个bean定义对应产生实例的类型,也 ...

  9. spring中注解属性scope的prototype是什么意思?

    默认情况下,从 bean工厂所取得的实例为Singleton(bean的singleton属性) Singleton: Spring容器只存在一个共享的bean实例,默认的配置. Prototype: ...

  10. 说说 Spring Bean 的作用域

    配置文件中定义 Bean 时,我们不但可以配置 Bean 的属性值以及相互之间的依赖关系,还可以定义 Bean 的作用域 .作用域会对 Bean 的生命周期和创建方式产生影响 . Bean 的作用域类 ...

最新文章

  1. shiro 全局变量定义
  2. Linux下undefined reference to ‘pthread_create’问题解决 zz
  3. 【Java SE】记录一次Java实验(多态,集合,泛型)
  4. linux系统如何管理文件
  5. 15 个实用的 PHP 正则表达式
  6. java 基础知识3
  7. vector public member function
  8. spring和mybatis整合代码
  9. make_heap,pop_heap,push_heap
  10. crontab使用方法
  11. Modbus PLC攻击分析:Smod渗透框架研究
  12. 北理乐学c语言数字菱形,打印数字菱形,急啊,帮帮小女子啊。。。
  13. CubeMX配置SPI-Flash(W25Q256)
  14. Linux 下安装和配置 MinDoc
  15. 影响网站收录的几个因素
  16. 数学——行向量和列向量
  17. c++程序设计练习2.1
  18. 祝贺Phyllis Turner女士成为世界上最年长的硕士!
  19. mysql%3e= %3c=某个时间_乐视网某站SQL注入3枚
  20. 制作flash动画的心得

热门文章

  1. @Transactional注解最容易忽视的三个失效场景!
  2. 伍六七带你学算法——被忽视的数学公式
  3. 2022-2028年中国电力行业节能减排投资分析及前景预测报告
  4. REST接口设计规范
  5. hadoop 添加删除机器以及设置免密登录
  6. html 实现动态在线预览word、excel、pdf等文件
  7. SQL case when
  8. oracle dba_tables各字段含义
  9. LeetCode简单题之将每个元素替换为右侧最大元素
  10. QNX Hypervisor管理程序