又踩到Dubbo的坑,但是这次我笑不出来( 二 )
源码细节阅读过源码 , 和对源码有细节深入思考 , 效果是很大不一样的 。
我们来看一下源码就知道了 。 文中说的会清楚 , 对应的代码是怎么样的呢?
文章插图
文章插图
如果作为正常的客户端调用 , 那么 , 在调用后确实是会删除的 。 但是如果你对源码细节足够熟悉你就会发现 , 在org.apache.dubbo.rpc.filter.ContextFilter这个类中 。
文章插图
文章插图
你不看代码直接听我说也行 , 这几段代码的意思是 , 在一个提供者的方法中 , canRemove会设置为false的 , 所以 , 他们在这个方法体远程调用中 , 是没办法清空RpcContext的 , 需要在整体调用完才会清空 。
我们再回顾一下案发现场
@Overridepublic String sayHello() throws Exception{bHelloService.sayHello();Thread.sleep(10L);bHelloService.sayHello();return "欢迎关注微信公众号:肥朝";}从目前得到的信息很明显知道 , 第一次远程调用 , 和第二次远程调用 , 用的是同一个RpcContext,并且 , 在第二次远程调用的时候 。 这个RpcContext的内容 , 给人动了手脚了 。
那么 , 究竟是何人所为!我们随着镜头 , 再次深入源码!既然是RpcContext给人搞了 , 那么我们就从这里顺藤摸瓜,这里先省略肥朝的内心戏 , 我们来看重点 。 在RpcContext中发现一段可疑片段
public static void restoreContext(RpcContext oldContext) {LOCAL.set(oldContext);}接着继续顺藤摸瓜,发现调用这段代码的逻辑是
/** * tmp context to use when the thread switch to Dubbo thread. */private RpcContext tmpContext;private RpcContext tmpServerContext;private BiConsumer看不懂代码不要怕 , 肥朝大白话解释一下 。 你就想象一个Dubbo异步场景 , Dubbo异步回调结果的时候 , 是会开启一个新的线程 , 那么 , 这个回调就和当初请求不在一个线程里面了 , 因此这个回调线程是拿不到当初请求的RpcContext 。 但是我们清空RpcContext是需要在一次请求结束的时候 , 也就是说 , 虽然异步回调是另外一个线程了 , 但是我们仍然需要拿到当初请求时候的RpcContext来走Filter , 做清空等操作 。 上面那段代码就是做 , 切换线程怎么拿回之前的RpcContext 。
听完上面的分析 , 你是不是明白了点啥?新线程 , 还能拿到旧的RpcContext 。 那么 , 有这么一个场景 , 我们在通过提供者方法中 , 发起两个异步请求 , 第一个请求走Filter的onResponse(响应结果)的时候 , 我们如果在Filter做RpcContext.getContext().setAttachment操作 , 第二个请求又正好发起 , 而发起又会经历putAll这步骤 , 就会出现这个并发修改异常 。 于是乎 , 真相大白!
拓展性思考真相大白就结束了?熟悉肥朝的粉丝都知道 , 我们遇到问题 , 要尽量压榨问题的全部价值!比如 , 你说不要在拦截器中onResponse方法中用RpcContext.getContext().setAttachment这样的操作 , 但是我们确实有类似需要 , 那到底要怎么写代码又不说 , 你这样叫我怎么给你转发文章!
- 王文鉴|从工人到千亿掌门人,征服华为三星,只因他36年只坚持做一件事
- 手机|这个超强App,让手机快3倍,流畅到起飞
- 巅峰|realme巅峰之作:120Hz+陶瓷机身+5000mAh 做到了颜值与性能并存
- 现货供应|卢伟冰说到做到!120Hz+一亿像素,狂销30万首销现货供应
- 打响|拼多多打响双12首枪,iPhone12降到“mini价”,苹果11再见
- 深度|iPhone12到底值得买吗 深度体验一周我发现了这些
- 不到|苹果赚了多少?iPhone12成本不到2500元,华为和小米的利润呢?
- 星期一|亚马逊:黑五与网络星期一期间 第三方卖家销售额达到48亿美元
- 权属|从数据悖论到权属确认,数据共享进路所在
- 月入|一上网,感觉网上每个人都是月入过万,到底是错觉还是你out了?
