php 静态变量可以多个子类共享,记一次抽象类中定义的静态变量,多个子类继承后,在方法中被重写引起的问题...

N年没有写过博客了……

开始:

2018.08.03  搬家项目,版本昨晚刚上线,今早测试与供应商的估价接口,发现问题。

背景:

我司对接三家供应商A、B、C,各家的Url,appid不同,分别配置在配置文件中。

抽象类(截取部分片段):

f5692f90f65d5d6a4098a203f2d6d88f9d5.jpg

a392f36cb4551b9c861dff303bf9c38947d.jpg

1 public abstract class AbstractSupplierOrderService implementsISupplierOrderService {2

3

4 protected staticISupplierConfig supplierConfig;5

6 @Autowired7 privateMovTaskMapper movTaskMapper;8

9 //根据供应商code 获取对应供应商服务实例

10 public staticISupplierConfig getSupplierConfig(String supplierCode) {11 if(SupplierEnum.LANXINIU.getCode().equals(supplierCode)) {12 return SpringContextUtil.getBean(SupplierConfigLanxiniu.class);13 }14 if(SupplierEnum.ZIROOM.getCode().equals(supplierCode)) {15 return SpringContextUtil.getBean(SupplierConfigZiroom.class);16 }17 if(SupplierEnum.SITONG.getCode().equals(supplierCode)) {18 return SpringContextUtil.getBean(SupplierConfigSitong.class);19 }20 return null;21 }22

23 @Override24 publicResultInfoVo quotedPrice(EvaluateOrderPriceVo orderVo) {25 supplierConfig =AbstractSupplierOrderService.getSupplierConfig(orderVo.getSupplierCode());26 String quotedPriceUrl =supplierConfig.getQuotedPriceUrl();27

28 ResultInfoVo resultInfoVo = null;29 EvaluateOrderPriceVo evaluateOrderPriceVo = null;30

31 try{32 Map voMap = ObjectToMapUtils.objectToMapString(null, orderVo, "");33 Map paramMap =getSupplierService(orderVo.getSupplierCode()).getOrderParams(voMap);34

35 log.info("=============调用供应商获取报价信息接口入参:{}=============", JSONObject.toJSONString(paramMap));36 resultInfoVo =postSupplierServices(orderVo.getSupplierCode(), evaluateRestTemplate, quotedPriceUrl, paramMap);37 } catch(Exception e) {38 log.error("=============调用供应商获取报价信息异常,入参:{}=============", JSONObject.toJSONString(orderVo), e);39 throw new OrderServiceException("调用供应商获取报价信息异常", e);40 }41

42 log.info("=============调用供应商获取报价信息接口出参:{}=============", JSONObject.toJSONString(resultInfoVo));43

44 returnresultInfoVo;45 }46

47 }

View Code

调用入口:

1 publicResultInfoVo evaluateOrderPrice(EvaluateOrderPriceVo evaluateOrderPriceVo) {2 ===========省略==========

3 log.info("========估价流程开始,供应商code:{}========", evaluateOrderPriceVo.getSupplierCode());4 //动态获取服务商实例

5 ISupplierOrderService supplierOrderService =AbstractSupplierOrderService.getSupplierService(evaluateOrderPriceVo.getSupplierCode());6 //调用供应商获取报价接口

7 try{8 quotedPriceResult =supplierOrderService.quotedPrice(evaluateOrderPriceVo);9 } catch(Exception e) {10 }11 ===========省略==========

12 }

抽象类中有静态变量:supplierConfig。而 静态变量位于抽象类类对象的方法区,三个实现子类共用该静态变量。 如各子类对该静态变量赋值需求不同,在多线程情况下,会出现问题。

排查问题时的日志:

09caeee9ccb1d6e417054de99bd63406.png

日志中可以看到,问题出在线程2,8。

分析:

线程2、1、8先后进入估价流程MovOrderService.evaluateOrderPrice,

1、线程8先根据对应的1003的supplierConfig实现,组装参数,生成sign。 实现类中取的 supplierConfig是在实现类中的一个类变量,所以不会共用抽象类中的类变量,取得apppid是对的

5b2c51bfab2c03e9cd676df8a79dedce.png

2、线程2根据抽象类中的静态类变量supplierConfig获取url。但此时supplierConfig被线程2更新成了线程2对应的实例,取的是线程2的对应配置。所以url取错了。

总结:多线程环境下,对于可变的变量,在抽象基类中,慎用静态变量。

因为各实现类都引用了基类的静态类变量(即便子类中自己定义了同名变量,也与基类中的变量不是一个存储空间)。该基类静态变量只有这么一个存储空间。 所以会很容易被修改,导致意想不到的结果。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值