Error creating bean with name ‘scopedTarget.configDictList’: Requested bean is currently in creation: Is there an unresolvable circular reference?
先说明下公司使用的场景:
字典表ConfigDict
,
所有对象都使用了监听@PreUpdate
@PrePersist
事件。(对ConfigDict
的修改会进入)。
为了使用方便,将字典交给了Spring管理。
@Bean(name = "configDictList")
@RefreshScope
public List<ConfigDict> list(){
return configDictRepository.findAll();
}
这里的@RefreshScope
是为了修改或者新增字典后会刷新bean。问题也正是加了动态刷新引起的。
Listener代码:
@PreUpdate
@PrePersist
void updateEnum(Object entity) {
LOGGER.debug("进入EnumFieldListener.class");
List<ConfigDict> list = (List<ConfigDict>) SpringContextHolder.getBean("configDictList"); // ①
}
看看修改字典的代码:
public Resp saveOrUpdate(@Validated @RequestBody ConfigDict configDict) {
configDictRepository.save(configDict); //②
refreshScope.refresh("configDictList"); // ③
return Resp.success(configDict);
}
问题场景:
更新一次字典后,下一个更新接口更新实体A,进入了监听器,并且尝试从容器中获取字典
。
①SpringContextHolder.getBean("configDictList")
这句代码将执行错误。
分析:
在③执行完后,将会把bean的缓存清空,代理对象还在,将会在下一次获取bean的实际去获取。
https://blog.csdn.net/tanhongwei1994/article/details/120147010
所以在执行②的时候会执行到configDictRepository.findAll()
去获取。
通过debug 这步执行过程中 又会到updateEnum方法中去。然后又获取这个bean,但是这个bean是在创建过程中了,导致了循环依赖
理论上是不应该再次进入updateEnum方法的。经过debug发现。
hibernate在执行完list方法获取后,会刷新当前会话,导致我们第二次进入更新实体A。
解决办法: configDictRepository.findAll()
不跟其他语句在一个会话,单独加个新事物的注解即可解决问题。
@Bean(name = "configDictList")
@RefreshScope
@Transactional(propagation = Propagation.REQUIRES_NEW)
public List<ConfigDict> list(){
return configDictRepository.findAll();
}