错误:"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的日志!然后仔细检查自己的代码,想想基础语法!!!