request对象_为什么Spring中的对象默认要设计成单例的

9f3121a84b921571474e01097f8856e1.png

AbstractBeanFactory中有一个doGetBean方法,spring容器中的bean都会走这个方法过,这个方法可以用于bean的BeanDefinition中信息来判断是单例还是多例,并创建返回:

6ff5d6c850f6d9f8a9019913996121d8.png

d2012787d4987c5aae35d04b4cc7aa18.png

我们在 else if (mbd.isPrototype())处打上断点,最终发现基本没有bean走到这一步:

89730031fa3343ba61ff41987d082f1c.png

然后我们在某个Bean上加上@Scope:

031701da5f477f8d2ccc8f945cc0d1ed.png

重新启动debug:

4e95de14780cd63cacf9dfaacdd65e23.png

====================

所以,问题来了:

  1. 为什么要设计成单例
  2. 单例的bean如何解决线程安全问题

对于第一点,可以理解为为了简化资源消耗,因为每有一个请求打到Controller层十,如果该Controller是原型,那么就会重新实例化一个对象,这样对于高并发的情况下消耗是相当大的,所以设计为单例,所有请求访问的都是同一个对象。

但是这样就会有一个缺点,那就是多线程的情况下如何解决线程安全问题,因为你都是访问的同一个controller对象啊,假如此时多个线程同时访问该controller的同一个方法(假设该方法对实例变量进行了操作),那不就有线程安全问题了吗?那你说可以在需要的方法上加上悲观锁不就好了,频繁的线程切换会消耗大量cpu时间,在高并发惜时如金的情况下显然不合适,所以可以采用以“空间”换“时间”的做法:

threadlocal

常见的有RequestContextHolder、TransactionSynchronizationManager等都是采用threadlocal,其中RequestContextHolder的作用是获取当前请求的上下文,比如request、session这些,在没有threadlocal的情况下,我们大概要写一个加了悲观锁的静态方法,方法内容是获取当前线程的request对象,然后当前线程作为key,request对象作为value存到一个全局map里面。

有了threadlocal之后,我只需将request对象set入当前线程thread的Threadlocal.threadlocalmap属性中,threadlocal实际上并没啥用,只是起到一个“钩子”的作用,存值的时候负责用set方法把request对象甩到当前线程的threadlocalmap的entry[]数组中,取值的时候负责将threadlocalmap的entry[]数组对应的值从当前线程中“钩”出来(是通过threadlocal来作为key从entry[]中存取值,所以叫钩子):

1dee2cd76d04b9aaefb42992fd5cfba8.png

除上图中的方法还有其他封装threadlocal的方法,这里就不细谈了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值