实际业务场景中大量if..else的优化:ApplicationContextAware的应用

一,业务背景

在公司做一个Canal数据同步的时候,我们需要根据CanalEntry中传过来的表名,获取到相应的实例,然后调用相应的新增,更新删除数据的方法,
当前的问题是如何根据表名获取到相应的实例呢?

比较直观的是通过if…else来判断然后返回new出对应的实例。
代码

    public IBaseDataOperateService getBeanByTableName(String tableName) {
        if(tableName.equals("表A"){
            return new CompanyProductServiceImpl();
        }else if(tableName.equals("表B")){
            return new RoleBaseDataOperateServiceImpl();
        }else if{
            .....
        }
        return null;
    }

二,分析

如果操作的表不再改变这样,好像也不是不行,但是如果突然有其他表也需要做数据同步到BI库了,那么代码每次都需要改变,就会有大量的if…else…而这样的代码也不符合公司开发规范。

如果能在spring初始化好Bean之后提前把表名和实例的映射放到map中,然后用到的时候直接get,就避免了大量if…else…的使用。

三,ApplicationContextAware

spring会给实现此接口的类注入ApplicationContext对象,
在这里插入图片描述
通过源码跟踪了解到AbstractApplicationContext.class下的refresh()方法中的prepareBeanFactory这句跟Aware有关,我们还可以看到:ApplicationContextAware是在spring初始化完bean后才注入上下文的
在这里插入图片描述
prepareBeanFactory方法中涉及到上图红圈圈这个类,此类中的方法postProcessBeforeInitialization调用了此类中的invokeAwareInterfaces方法:
在这里插入图片描述
接下来进行代码改造,

@Slf4j
@Component
public class BaseDataSyncSelector implements ApplicationContextAware {

    private Map<String, IBaseDataOperateService> baseDataOperateServiceMap;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, IBaseDataOperateService> beansOfType = applicationContext.getBeansOfType(IBaseDataOperateService.class);
        baseDataOperateServiceMap = new HashMap<>(beansOfType.size());
        for (Map.Entry<String, IBaseDataOperateService> baseDataOperateServiceEntry : beansOfType.entrySet()) {
            IBaseDataOperateService value = baseDataOperateServiceEntry.getValue();
            baseDataOperateServiceMap.put(value.tableName(), value);
        }
    }


    /**
     * 根据表名获取相应的处理service
     *
     * @param tableName 表名
     * @return
     */
    public IBaseDataOperateService getBeanByTableName(String tableName) {
        return baseDataOperateServiceMap.get(tableName);
    }
}

然后再BaseServcie中进行调用,完美解决!

    private void updateData(String tableName, List<CanalEntry.Column> beforeColumnsList,List<CanalEntry.Column> afterColumnsList) {
        try {
            //判断前后数据是否一致 如果一致则不处理
            if(compareData(beforeColumnsList,afterColumnsList)){
                return;
            }
            IBaseDataOperateService tableOperateService = baseDataSyncSelector.getBeanByTableName(tableName);
            if (tableOperateService != null) {
                tableOperateService.updateData(afterColumnsList);
            }
        }catch (Exception e){
            log.warn("update data error,tableName:{},beforeColumnsList:{},afterColumnsList:{}", tableName,JSON_UTILS.toJson(beforeColumnsList), JSON_UTILS.toJson(beforeColumnsList));
        }
    }
  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值