已知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 {
@Autowired
private SingletonService singletonService;
private Integer controllerIndex = 1; @RequestMapping("/singleton")
@ResponseBody
public 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 {
@Autowired
private PrototypeService prototypeService;
private Integer controllerIndex = 1; @RequestMapping("/prototype")
@ResponseBody
public 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 结论

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

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

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

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

【Spring】bean的作用域(@Scope) - singleton、prototype的更多相关文章

  1. Spring bean的作用域和生命周期

    bean的作用域 1.singleton,prototype, web环境下:request,session,gloab session 2.通过scope="" 来进行配置 3. ...

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

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

  3. Spring Bean的作用域(转)

    Spring Bean的作用域 .singleton  [单例] eg:<bean id="personService" class="com.yinger.ser ...

  4. spring bean的作用域和自动装配

    1 Bean的作用域 l  singleton单列:整个容器中只有一个对象实例,每次去访问都是访问同一个对象  默认是单列 l  prototype原型: 每次获取bean都产生一个新的对象,比如Ac ...

  5. Spring bean的作用域以及生命周期

    一.request与session的区别 request简介 request范围较小一些,只是一个请求. request对象的生命周期是针对一个客户端(说确切点就是一个浏览器应用程序)的一次请求,当请 ...

  6. spring bean 的作用域

    spring bean 的作用域: 1.单例(singleton):默认是单例模式,也就是说不管给定的bean被注入到其他bean多少次,注入的都是同一个实例. 2.原型(prototype):每次注 ...

  7. Spring——Bean的作用域

    Spring中Bean的作用域有五种,分别是singleton.prototype.request.session.globalSession.其中request.session.globalSess ...

  8. Bean的作用域scope

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

  9. spring bean 的作用域之间有什么区别

    spring bean 的作用域之间有什么区别? spring容器中的bean可以分为五个范围.所有范围的名称都是说明的, 1.singleton:这种bean范围是默认的,这种范围确保不管接受到多个 ...

  10. spring中bean的作用域属性singleton与prototype的区别

    1.singleton 当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会 ...

随机推荐

  1. 超链接a标签的伪类选择器问题,Link标签与visited标签的失效问题(问题介绍与解决方法)。

    <!DOCTYPE html>< html>< head>     <meta charset="utf-8" />     < ...

  2. 低功耗设计技术--Multi VDD--Level shifter

    本文转自:自己的微信公众号<集成电路设计及EDA教程> 前面的推文中我们分别介绍了低功耗设计中的Multi-VDD技术以及门控电源技术.在实际的低功耗设计中,门控电源技术中也常常结合Mul ...

  3. javase第一章(了解java)

    ------------恢复内容开始------------ java介绍 java这门语言,如果你是一名IT从业者,那么就一定是会有所耳闻的,毕竟,这是编程史上其商业化最成功的一门语言,当然, 编程 ...

  4. python序列化对象和反序列化

    1.首先不管哪种语言都会用到序列化和反序列化的过程, 2.序列化:把对象转换为字节序列的过程称为对象的序列化:   反序列化:把对象转换为字节序列的过程称为对象的序列化. 3.序列化的作用:把对象(变 ...

  5. Codeforces_714_A

    http://codeforces.com/problemset/problem/714/A 水,注意K的值. #include <iostream> using namespace st ...

  6. ZOJ 4067 Books (2018icpc青岛J) (贪心)

    题意 给你一个长度为n的数组,代表每一个物品的价格.你有一个初始钱数\(x\),采用以下方法贪心: 从\(1\)到\(n\)扫一遍,如果\(x\)不比\(a[i]\)小,就买下它,买不起就跳过. 给你 ...

  7. 小白学 Python 数据分析(4):Pandas (三)数据结构 DataFrame

    在家为国家做贡献太无聊,不如跟我一起学点 Python 人生苦短,我用 Python 前文传送门: 小白学 Python 数据分析(1):数据分析基础 小白学 Python 数据分析(2):Panda ...

  8. Go语言实现:【剑指offer】整数中1出现的次数(从1到n整数中1出现的次数)

    该题目来源于牛客网<剑指offer>专题. 求出1 ~ 13的整数中1出现的次数,并算出100 ~ 1300的整数中1出现的次数?为此他特别数了一下1 ~ 13中包含1的数字有1.10.1 ...

  9. USBWebServer - 在U盘里搭一个Web服务器!

    文章选自我的博客:https://blog.ljyngup.com/archives/321.html/ 本文将介绍一款可以在U盘内直接搭建Web服务器的软件 软件可以免安装直接在U盘内运行,适合外出 ...

  10. vue 过渡 & 动画

    过渡 & 动画 过渡动画 用css先定义好动画效果 .a-enter-active, .a-leave-active { transition: all 1.5s; } .a-enter, . ...