Spring依赖注入与getBean不同实例问题

问题描述

线上的原来的过滤链配置是通过@Resource写死配置在一个配置文件Bean内,新版本使用页面配置可以随时更新配置,根据bean的名称通过getBean的方式获取对应的实例。两者都是通过spring容器维护的单例bean。迁移新配置期间服务会比较两者配置不一致时输出冲突日志。已经上线很久,当发现冲突时页面配置调整为一致则不会再有冲突日志。但是这次突然疯狂打印起了冲突日志。而且我们去核对代码中写死的配置与页面的配置是完全一致的。一致的配置为什么会打印冲突呢?
冲突日志:

filters and newFilters are conflicted, platformId:18, orderType:0,contractType:0,filter:[OfflineRiderFilter, ImportantOrderRiderLevelFilter, NormalRiderLevelFilter, TakeModeFilter, RiderUnAuditedFilter, RiderForbiddenFilter, OrderGrabNotInReceivingAreaFilter, RiderOrderCityMismatchFilter, RiderDepositGrabFilter, RiderRiskTagGrabFilter, SwitchOrderFilter, ContractRiderFilter, RiderTagFilter, SwitchOrderTimesLimitFilter, OrderCellingFilter, RiderWithImportantOrderFilter, RiderWithExpressOrderFilter]

问题分析

因为之前修改过一次比较两个集合的方法。原本使用的是自己写的比较方法,只要bean的class是同一个即可。后来改用了工具类判断:CollectionUtils.isEqualCollection
查看其对应的源码实现

public static boolean isEqualCollection(final Collection<?> a, final Collection<?> b) {
    if(a.size() != b.size()) {
        return false;
    }
    // 复制两个集合,复制后的属性为final即不可修改。复制的集合为map,key为集合元素的实例,
    // value为Integer类型的计数器,发现集合中有多个相同实例时会递增,默认都是1个。
    // value中的Integer是从静态池中获取的,性能很好
    // 所有的属性均为final类型,所以不存在并发问题,除非有人对map中的数据增删改,但是并没有
    final CardinalityHelper<Object> helper = new CardinalityHelper<Object>(a, b);
    if(helper.cardinalityA.size() != helper.cardinalityB.size()) {
        return false;
    }
    // 比较实例是否相等,freqA、freqB返回的都是解包后的数据,也就是int,
    // 即使前面发现相同的实例个数超出静态池缓存限制(默认为-128-127)重新创建的两个新实例比如:256
    // 也不会因为实例不同导致比较失败
    for( final Object obj : helper.cardinalityA.keySet()) {
        if(helper.freqA(obj) != helper.freqB(obj)) {
            return false;
        }
    }
    return true;
}

可以看到该工具类的实现是会比较实例是否相同的,如果说同一个class确实出现了两个不同的实例,则比较一定是返回false即不同的集合
那么会不会是因为这个原因呢?于是我们查看了服务上次重启时的配置的实例列表与最新冲突发生时配置的实例列表,发现果然是这个原因,两个列表的配置完全相同,class相同,但是却不是相同的实例。
问题至此已经解决。但是@Resource的方式与上下文getBean的方式获取同一个类型的Bean为什么会得到两个不同的实例呢?Bean都是采用单例方式注入使用的。而且之前发生不一致通过页面配置后便不会再打印冲突日志,也就是两个集合相等是完全相同的实例。为什么这次得到的是不同的实例?并且我们其他的服务同样的代码却没有打印冲突日志。只有两个服务出现了这个情况。原因还需要进一步分析。

// 更新配置前
grabFilterMap:{plat:0_ord:0_cont0=[FilterConfigCache.FilterDTO(filter=OfflineRiderFilter@49206065), FilterConfigCache.FilterDTO(filter=ImportantOrderRiderLevelFilter@3c0bbc9f), FilterConfigCache.FilterDTO(filter=NormalRiderLevelFilter@1317b708), FilterConfigCache.FilterDTO(filter=TakeModeFilter@6438a7fe), FilterConfigCache.FilterDTO(filter=RiderUnAuditedFilter@4f5f6e45), FilterConfigCache.FilterDTO(filter=RiderForbiddenFilter@1866da85), FilterConfigCache.FilterDTO(filter=OrderGrabNotInReceivingAreaFilter@4cfa8227), FilterConfigCache.FilterDTO(filter=RiderOrderCityMismatchFilter@78226c36), FilterConfigCache.FilterDTO(filter=RiderDepositGrabFilter@3f685162), FilterConfigCache.FilterDTO(filter=RiderRiskTagGrabFilter@11f406f8), FilterConfigCache.FilterDTO(filter=SwitchOrderFilter@615e3f51), FilterConfigCache.FilterDTO(filter=ContractRiderFilter@407873d3), FilterConfigCache.FilterDTO(filter=RiderTagFilter@5412bfea), FilterConfigCache.FilterDTO(filter=SwitchOrderTimesLimitFilter@381d7219), FilterConfigCache.FilterDTO(filter=RiderBlacklistFilter@49fe3142), FilterConfigCache.FilterDTO(filter=OrderCellingFilter@13fed1ec), FilterConfigCache.FilterDTO(filter=RiderWithImportantOrderFilter@61c42416), FilterConfigCache.FilterDTO(filter=RiderWithExpressOrderFilter@574cd322)]},remoteClientVersion:505
// 更新配置后
grabFilterMap:{plat:0_ord:0_cont0=[FilterConfigCache.FilterDTO(filter=OfflineRiderFilter@3cb8c8ce), FilterConfigCache.FilterDTO(filter=ImportantOrderRiderLevelFilter@1fde0371), FilterConfigCache.FilterDTO(filter=NormalRiderLevelFilter@70c0a3d5), FilterConfigCache.FilterDTO(filter=TakeModeFilter@5c8e67b9), FilterConfigCache.FilterDTO(filter=RiderUnAuditedFilter@49206065), FilterConfigCache.FilterDTO(filter=RiderForbiddenFilter@72825400), FilterConfigCache.FilterDTO(filter=OrderGrabNotInReceivingAreaFilter@19ee1ae6), FilterConfigCache.FilterDTO(filter=RiderOrderCityMismatchFilter@5f117b3d), FilterConfigCache.FilterDTO(filter=RiderDepositGrabFilter@1174a305), FilterConfigCache.FilterDTO(filter=RiderRiskTagGrabFilter@71b6d77f), FilterConfigCache.FilterDTO(filter=SwitchOrderFilter@3c0bbc9f), FilterConfigCache.FilterDTO(filter=ContractRiderFilter@1317b708), FilterConfigCache.FilterDTO(filter=RiderTagFilter@2e51d054), FilterConfigCache.FilterDTO(filter=SwitchOrderTimesLimitFilter@608bc8f8), FilterConfigCache.FilterDTO(filter=OrderCellingFilter@44a6a68e), FilterConfigCache.FilterDTO(filter=RiderWithImportantOrderFilter@4743a322), FilterConfigCache.FilterDTO(filter=RiderWithExpressOrderFilter@2ec3633f)]},remoteClientVersion:574
// 再次更新后所有的bean均又不一样
grabFilterMap:{plat:0_ord:0_cont0=[FilterConfigCache.FilterDTO(OfflineRiderFilter@49206065), FilterConfigCache.FilterDTO(ImportantOrderRiderLevelFilter@3c0bbc9f), FilterConfigCache.FilterDTO(NormalRiderLevelFilter@1317b708), FilterConfigCache.FilterDTO(TakeModeFilter@6438a7fe), FilterConfigCache.FilterDTO(RiderUnAuditedFilter@4f5f6e45), FilterConfigCache.FilterDTO(RiderForbiddenFilter@1866da85), FilterConfigCache.FilterDTO(OrderGrabNotInReceivingAreaFilter@4cfa8227), FilterConfigCache.FilterDTO(RiderOrderCityMismatchFilter@78226c36), FilterConfigCache.FilterDTO(RiderDepositGrabFilter@3f685162), FilterConfigCache.FilterDTO(RiderRiskTagGrabFilter@11f406f8), FilterConfigCache.FilterDTO(SwitchOrderFilter@615e3f51), FilterConfigCache.FilterDTO(ContractRiderFilter@407873d3), FilterConfigCache.FilterDTO(RiderTagFilter@5412bfea), FilterConfigCache.FilterDTO(SwitchOrderTimesLimitFilter@381d7219), FilterConfigCache.FilterDTO(OrderCellingFilter@13fed1ec), FilterConfigCache.FilterDTO(RiderWithImportantOrderFilter@61c42416), FilterConfigCache.FilterDTO(RiderWithExpressOrderFilter@574cd322)]},remoteClientVersion:575

Resource注解与上下文getBean注入问题分析

回头又看了源码想破脑袋也没能想出该场景出现的原因。。。
google了一下大体有两个方向的可能,地址:https://stackoverflow.com/questions/11547240/spring-creating-multiple-instances-of-a-singleton

  1. 存在多个ApplicationContext上下文
  2. 存在重复的scan路径配置导致重复扫描了两次目录
发布了81 篇原创文章 · 获赞 85 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/u010597819/article/details/99226513
今日推荐