记一次奇怪的BUG

错误:"Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'searchAreaController': Unsatisfied dependency expressed through method 'setSearchAreaService' parameter 0; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'searchAreaServiceImpl' is expected to be of type 'com.ngsoc.view.service.impl.SearchAreaServiceImpl' but was actually of type 'com.sun.proxy.$Proxy167'"

排查原因:在controller层里面,同一个调用了两次service实例,并且前后两次使用的实例不一致,导致服务宕机。

controller代码

  @Setter(onMethod_ = @Autowired)
    private SearchAreaServiceImpl searchAreaService;

    @PostMapping("/{viewInstanceId}")
    @ApiOperation("保存检索区配置")
    @OperateLog(target = "search", action = "save")
    @PreAuthorize("hasAnyAuthority(@viewInstancePolicyParser.parse(#viewInstanceId))")
    public void save(
            @PathVariable("viewInstanceId") @Pattern(regexp = ValidationConstants.ID_PATTERN, message = "Invalid viewInstanceId") String viewInstanceId,
            @RequestBody @Validated SearchArea search
    ) {
        searchAreaService.update(new ObjectId(viewInstanceId), search);
        searchAreaService.updateSearchHistories(search);
    }

service代码

@Service
@CustomLog
public class SearchAreaServiceImpl extends AbstractAreaService<SearchArea> implements SearchAreaService {

    @Setter(onMethod_ = @Autowired)
    private SearchHistoriesDao searchHistoriesDao;

    @Override
    public Update getUpdate(SearchArea area) {
        Update update = new Update();
        update.set(ViewCoreConstants.VIEW_SEARCH, area);
        searchHistoriesDao.updateSearchHistories(area);
        return update;
    }

 父类代码

public abstract class AbstractAreaService<T> {
    @Setter(onMethod_ = @Autowired)
    protected MongoTemplate viewMongoTemplate;

    /**
     * 获取更新对象
     *
     * @param area 区域
     * @return 更新对象
     */
    public abstract Update getUpdate(T area);

    /**
     * 更新区域
     *
     * @param viewInstanceId 实例id
     * @param area           区域
     */
    public final void update(ObjectId viewInstanceId, T area) {
        final Update update = getUpdate(area);
        final Query query = Query.query(Criteria.where(ViewCoreConstants.MONGO_ID).is(viewInstanceId));
        if (!viewMongoTemplate.exists(query, ViewInstance.class)) {
            throw new ViewNotFoundException(
                    I18nUtils.i18n("exception.view.instance.not.exists", viewInstanceId.toHexString())
            );
        }
        UpdateResult updateResult = viewMongoTemplate.updateFirst(query, update, ViewInstance.class);
        if (updateResult.getMatchedCount() == 0) {
            throw new ViewUpdateException(
                    I18nUtils.i18n("exception.view.update", "searchArea", viewInstanceId.toString())
            );
        }
    }
}

SearchAreaServiceImpl继承了AbstractAreaService,并且实现了SearchAreaService,由于Spring注册bean,同类型只会注册一次,所以第一次只会注册AbstractAreaService的父类特性,所以,只会调用update方法,第二次来注册SearchAreaService时,由于Spring只会注册一次,请求还未走完,所以找不到SearchAreaService父类型的bean,导致容器找不到对应的bean,Spring一直重试注册bean,最终服务宕机。

解决办法:不在controller层里面调用两次,把service的方法写到下一层dao层,在service层调用原来的逻辑。

PS:百度查到的和自己的情况不一样,这个BUG共花了14个小时,之前一直没怎么仔细看代码,因为k8s的pod一直重启,以为是环境问题,换了很多环境还是不行,才想起来看代码,最后,使用笨办法一段逻辑一段逻辑重写去排查任务,终于是在最后一段逻辑排查出来了。

注意:一定要看k8s的日志!然后仔细检查自己的代码,想想基础语法!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值