zoukankan      html  css  js  c++  java
  • 记一次抽象类中定义的静态变量,多个子类继承后,在方法中被重写引起的问题

    N年没有写过博客了……

    开始:

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

    背景:

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

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

     1 public abstract class AbstractSupplierOrderService implements ISupplierOrderService {
     2 
     3 
     4     protected static ISupplierConfig supplierConfig;
     5 
     6     @Autowired
     7     private MovTaskMapper movTaskMapper;
     8 
     9     //根据供应商code 获取对应供应商服务实例
    10     public static ISupplierConfig 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     @Override
    24     public ResultInfoVo 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         return resultInfoVo;
    45     }
    46 
    47 }
    View Code

    调用入口:

     1 public ResultInfoVo 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。而 静态变量位于抽象类类对象的方法区,三个实现子类共用该静态变量。 如各子类对该静态变量赋值需求不同,在多线程情况下,会出现问题。

    排查问题时的日志:

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

    分析:

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

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

         

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

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

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

  • 相关阅读:
    2017免费获取正版win10的方法
    Apache <Directory>… </Directory>配置
    针对left join以及limit的两条优化小技巧
    win10打印机突然无法启动
    mysql中的分组统计函数及其用法实例
    程序猿的日常生活-雨中
    java中的反射
    mysql中的截取函数及其实例
    集合与数组
    方法重写
  • 原文地址:https://www.cnblogs.com/jinianjun/p/9419523.html
Copyright © 2011-2022 走看看