监听事件解决循环依赖问题

最近在工作中遇到了代码中循环依赖的问题,记录下解决方案。

1.问题原因

这里涉及到两个类YgReplenishmentAppService(补货单处理)和YgPurchaseOrderAppService(采购单处理)
我们看下类中的代码:

@Slf4j
@Service
public class YgReplenishmentAppService {
 	private YgPurchaseOrderAppService ygPurchaseOrderAppService;
 	
 	private void getHotelEstimateNumber(Set<String> skuSet, Map<Long, Map<String, BigDecimal>> hotelEstimateNumberMap, Long hotelId) {
        // 预计可用数量
        List<String> skuNoList = new ArrayList<>(skuSet);
        List<InventoryForecastItem> inventoryForecastItemList = inventoryAppService.queryInventoryForecastByHotel(skuNoList, hotelId);
        // 补货申请
        inventoryForecastItemList.addAll(queryReplenishmentItem(hotelId, skuNoList));
        // 采购订单
        inventoryForecastItemList.addAll(ygPurchaseOrderAppService.queryPurchaseOrderItem(hotelId, skuNoList));
        // 填充运营物品分类编码
        for(InventoryForecastItem forecastItem:inventoryForecastItemList){
            StatsGroupInfoVO statsGroupInfoBySkuNo = statsGroupInfoRepostitory.getStatsGroupInfoBySkuNo(forecastItem.getSkuNo());
            if(ObjectUtils.isEmpty(statsGroupInfoBySkuNo)){
                log.info("未获取到商品{}的运营物品分类信息,将不做补货处理",forecastItem.getSkuNo());
                continue;
            }
            forecastItem.setGoodsClassifyCode(statsGroupInfoBySkuNo.getGroupInfoCode());
            forecastItem.setGoodsClassifyName(statsGroupInfoBySkuNo.getValueDesc());
        }
        //剔除没有运营物品编码的商品
        List<InventoryForecastItem> activeInventoryForecastItemList = inventoryForecastItemList.stream().filter(item -> item.getGoodsClassifyCode() != null).collect(Collectors.toList());
        //按照运营物品分组
        Map<String, List<InventoryForecastItem>> skuInventoryForecastMap = activeInventoryForecastItemList.stream().collect(Collectors.groupingBy(InventoryForecastItem::getGoodsClassifyCode));
        if (skuInventoryForecastMap != null) {
            Map<String,BigDecimal> estimateNumberMap = new HashMap<>();
            for(String classifyCode:skuInventoryForecastMap.keySet()){
                BigDecimal estimateNumber = skuInventoryForecastMap.get(classifyCode).stream().map(InventoryForecastItem::getNumber).reduce(BigDecimal.ZERO, BigDecimal::add);
                estimateNumberMap.put(classifyCode,estimateNumber);
            }
            hotelEstimateNumberMap.put(hotelId,estimateNumberMap);
        }
    }
}


@Slf4j
@Service
public class YgPurchaseOrderAppService {
 @Autowired
    private YgReplenishmentAppService ygReplenishmentAppService;

    /**
     * 创建或者编辑易购采购订单
     *
     * @param dto 创建入参
     * @throws BizsException 异常
     */
    @Transactional(rollbackFor = Exception.class)
    public void createOrUpdateYgPurchaseOrder(YgPurchaseOrderInboundDTO dto) throws BizsException {
        // 查询对应的酒店信息
        YgPurchaseOrderContextDTO ctxDto = buildContextDto(dto);
        // 新建或者更新已存在的旧数据
        YgPurchaseOrder model = ygPurchaseOrderRepository.queryWholeByOrderNo(dto.getOrderNo());
        if (null == model) {
            model = YgPurchaseOrder.create(dto, ctxDto);
            ygPurchaseOrderRepository.insert(model);
        } else {
            model.update(dto, ctxDto);
            boolean result = ygPurchaseOrderRepository.update(model);
            if (!result) {
                throw new BizsException(ResultEnum.DOCUMENT_UPDATE_ERROR);
            }
        }
        // 调用补货服务方法, 对补货记录进行回写
        try {
            YgPurchaseOrderSyncDTO syncDto = BeanUtil.mapByJson(model, YgPurchaseOrderSyncDTO.class);
            ygReplenishmentAppService.syncReplenishmentByYgPurchaseOrderSyncDto(syncDto);
        } catch (Exception e) {
            log.error("易购采购订单回写失敗, 订单:[{}]  异常:{}", model, e);
        }
    }
}

可以看到在YgReplenishmentAppService中调用了ygPurchaseOrderAppService中的方法,而在ygPurchaseOrderAppService中同样调用了YgReplenishmentAppService中的方法,这样就造成了两个类存在循环依赖的问题。

2.解决方案

思路是将相互依赖的两个类进行解耦操作。可以引入第三方的方法去达到目的。这里是引入事件的处理模式,当收到采购订单时触发补货记录单的回写事件,从而避免在ygPurchaseOrderAppService中直接调用补货处理类(YgReplenishmentAppService)
具体看如下代码:

@Slf4j
@Service
public class YgPurchaseOrderAppService {
	 @Autowired
    private ApplicationContext applicationContext;

    /**
     * 创建或者编辑易购采购订单
     *
     * @param dto 创建入参
     * @throws BizsException 异常
     */
    @Transactional(rollbackFor = Exception.class)
    public void createOrUpdateYgPurchaseOrder(YgPurchaseOrderInboundDTO dto) throws BizsException {
        // 查询对应的酒店信息
        YgPurchaseOrderContextDTO ctxDto = buildContextDto(dto);
        // 新建或者更新已存在的旧数据
        YgPurchaseOrder model = ygPurchaseOrderRepository.queryWholeByOrderNo(dto.getOrderNo());
        if (null == model) {
            model = YgPurchaseOrder.create(dto, ctxDto);
            ygPurchaseOrderRepository.insert(model);
        } else {
            model.update(dto, ctxDto);
            boolean result = ygPurchaseOrderRepository.update(model);
            if (!result) {
                throw new BizsException(ResultEnum.DOCUMENT_UPDATE_ERROR);
            }
        }
		//这里将数据封装,并触发事件,让第三方处理,不再直接调用ygPurchaseOrderAppService
        YgOrderCreatedOrUpdated ygOrderCreatedOrUpdated = new YgOrderCreatedOrUpdated();
        ygOrderCreatedOrUpdated.setYgPurchaseOrder(model);
        applicationContext.publishEvent(ygOrderCreatedOrUpdated);
    }
}

上面提交了事件之后需要监听事件,去处理余下逻辑:

@Slf4j
@Component
public class YgOrderCreatedOrUpdatedListener {

    private YgReplenishmentAppService ygReplenishmentAppService;

    @TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
    public void onApplicationEvent(YgOrderCreatedOrUpdated ygOrderCreatedOrUpdated) {
        // 调用补货服务方法, 对补货记录进行回写
        YgPurchaseOrder model = ygOrderCreatedOrUpdated.getYgPurchaseOrder();
        try {
            YgPurchaseOrderSyncDTO syncDto = BeanUtil.mapByDozer(model, YgPurchaseOrderSyncDTO.class);
            ygReplenishmentAppService.syncReplenishmentByYgPurchaseOrderSyncDto(syncDto);
        } catch (Exception e) {
            log.error("易购采购订单回写失敗, 订单:[{}]  异常:{}", model, e);
        }
    }

    @Autowired
    public void setYgReplenishmentAppService(YgReplenishmentAppService ygReplenishmentAppService) {
        this.ygReplenishmentAppService = ygReplenishmentAppService;
    }
}

这样就可以成功解耦采购单和补货处理之间的依赖关系,后面遇到类似问题触类旁通。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值