其他分享
首页 > 其他分享> > 修改单例属性引发的血案

修改单例属性引发的血案

作者:互联网

背景

最近接触的一些系统中遇到一个问题,一个交易的服务对外提供了支付和退款两种能力,但是发现运行时交易的服务走了退款。
原因是spring容器管理的一个对象service 属性运行时被改变,导致上下流程对不上的问题,多业务链路并发时引发运行时属性错乱,导致 支付和退款行为混淆
下面是大体代码样例。记录下问题原因

样例

1、定义一个核心支付服务

public interface CoreService {

    public BaseResult trade(TradeParam tradeParam);
}

2、抽象两个业务单元 验证和执行


public interface TradeService extends CoreService{

    public VerificationService getVerificationService();

    public void setVerificationService(VerificationService VerificationService);

    public OperationService getOperationService();

    public void setOperationService(OperationService OperationService);
}

3、实现共享逻辑代码

@Service
public class TradeServiceImpl implements TradeService{

    private VerificationService verificationService;

    private OperationService operationService;

    @Override
    public VerificationService getVerificationService() {
        return this.operationService;
    }

    @Override
    public void setVerificationService(VerificationService verificationService) {
        this.verificationService=verificationService;
    }

    @Override
    public OperationService getOperationService() {
        return verificationService;
    }

    @Override
    public void setOperationService(OperationService OperationService) {
        this.operationService = operationService;
    }

    @Override
    public BaseResult trade(TradeParam tradeParam) {
        getVerificationService().verification(tradeParam);
        getOperationService().operate(tradeParam);
        return null;
    }
}

4、实现支付链路


public class PayServiceImpl implements CoreService{


    @Autowired
    @Qualifier("payVerificationService")
    private VerificationService payVerificationService;

    @Autowired
    @Qualifier("tradeService")
    private TradeService tradeService;

    @Autowired
    @Qualifier("payOperationService")
    private OperationService payOperationService;


    @Override
    public BaseResult trade(TradeParam tradeParam) {
        tradeService.setVerificationService(payVerificationService);
        tradeService.setOperationService(payOperationService);
        return tradeService.trade(tradeParam);
    }
}

5、实现退款链路

public class RefundServiceImpl implements CoreService{


    @Autowired
    @Qualifier("refundVerificationService")
    private VerificationService refundVerificationService;

    @Autowired
    @Qualifier("tradeService")
    private TradeService tradeService;

    @Autowired
    @Qualifier("refundOperationService")
    private OperationService refundOperationService;


    @Override
    public BaseResult trade(TradeParam tradeParam) {
        tradeService.setVerificationService(refundVerificationService);
        tradeService.setOperationService(refundOperationService);
        return tradeService.trade(tradeParam);
    }
}

经上方案实现落地后, 支付和退款业务并发时就有概率导致支付和退款运行时对应的实际逻辑单元混乱,导致要支付的实际退款,要退款的实际支付的事情发生。 因为tradeService服务是容器管理的单例,多链路并发修改了单例内的属性,导致运行时故障

方案

修改的方式有很多,最终只要保证运行时的节点数据不存在被覆盖的目的即可。
最简单的替换方案就是将两个set值的逻辑类去掉,改为bean初始化时注入,支付和退款各自初始化一个不同的tradeService即可

标签:OperationService,VerificationService,血案,private,tradeParam,单例,tradeService,publi
来源: https://blog.csdn.net/xupeng874395012/article/details/114096170