范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

Spirng循环依赖报错Isthereanunresolvablecircularreference?

  1:前言
  最近在项目中遇到了一次循环依赖报错的问题,虽然解决的很快,但是有些不明白的地方,特此记录。
  在此我把 bean 的结构和 注入方式单独拎出来进行演示 1.1:报错提示
  1.2:错误日志Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name "brokenComponent": Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name "tubunComponent" defined in class path resource [com/dev/config/sprngcache3/TwConfig.class]: Unsatisfied dependency expressed through method "tubunComponent" parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name "denpaComponent": Unsatisfied dependency expressed through field "tolenComponent"; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name "tolenComponent": Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name "tubunComponent": Requested bean is currently in creation:Is there an unresolvable circular reference? 1.3:stack overflow问题描述
  Requested bean is currently in creation: Is there an unresolvable circular reference?
  点击进入 stack overflow 问题描述 1.4:bean 依赖结构
  BrokenComponent: @Component public class BrokenComponent {      @Autowired     private TolenComponent tolenComponent;     @Resource     private TubunComponent tubunComponent; }
  TolenComponent: @Transactional @Component public class TolenComponent {      @Resource     private TubunComponent tubunComponent;  }
  TubunComponent: public class TubunComponent {      private DenpaComponent denpaComponent;      public TubunComponent(DenpaComponent denpaComponent) {         this.denpaComponent = denpaComponent;     } }
  TwConfig: @Configuration public class TwConfig {      @Bean     public TubunComponent tubunComponent(DenpaComponent denpaComponent) {         return new TubunComponent(denpaComponent);     } }
  DenpaComponent: @Component public class DenpaComponent {      @Autowired     private TolenComponent tolenComponent; }
  除了 tubunComponent 是构造器注入,其他的bean 都是set 注入。
  分析bean依赖图可以发现确实是循环依赖的问题。 2:问题分析
  由于本人对spring bean 的加载机制不是很清晰,这次特意花了几天时间做了梳理。 2.1:spring 的 bean 加载过程
  2.2:spring 的三级缓存
  解决了什么问题?
  推荐博客:https://cloud.tencent.com/developer/article/1497692 2.3:Spring 容器加载过程中比较重要的类/属性
  类名称
  方法
  作用
  DefaultListableBeanFactory
  preInstantiateSingletons
  Trigger initialization of all non-lazy singleton beans.../ 触发所有非懒加载的单例bean进行初始化
  AbstractBeanFactory
  getBean/doGetBean
  从容器中获取bean
  DefaultSingletonBeanRegistry
  getSingleton
  从缓存中获取单例实例,没有则走单例的创建流程
  DefaultSingletonBeanRegistry
  beforeSingletonCreation
  创建单例之前会将单例放在set集合(singletonsCurrentlyInCreation)中,有检查bean是否被循环依赖的作用
  DefaultSingletonBeanRegistry
  beforeSingletonCreation
  创建单例之后会将单例从set集合(singletonsCurrentlyInCreation)中移除
  AbstractAutowireCapableBeanFactory
  createBean/doCreateBean
  创建单例bean
  AbstractAutowireCapableBeanFactory
  populateBean
  对bean进行属性赋值(往往是二级缓存中的bean)
  AbstractAutowireCapableBeanFactory
  initializeBean
  对属性赋值之后的bean进行初始化,加载RootBeanDefinition信息,这一步做完才是一个完整的可用的beanpublic class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {  	/** Cache of singleton objects: bean name to bean instance.(一级缓存,存放已初始化完毕的bean) */ 	private final Map singletonObjects = new ConcurrentHashMap<>(256);  	/** Cache of singleton factories: bean name to ObjectFactory.(三级缓存,存放未进行过初始化的beanFactory) */ 	private final Map> singletonFactories = new HashMap<>(16);  	/** Cache of early singleton objects: bean name to bean instance. (二级缓存,存放已实例化,但未进行装配过属性的bean)*/ 	private final Map earlySingletonObjects = new HashMap<>(16);  	/** Set of registered singletons, containing the bean names in registration order.(存放已注册了的单例集合 = singletonObjects.size + earlySingletonObjects)*/ 	private final Set registeredSingletons = new LinkedHashSet<>(256);  	/** Names of beans that are currently in creation.(存放正在被创建的实例,用于检查是否有循环依赖) */ 	private final Set singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));          .... } 2.4:注册后处理器->BeanPostProcessor
  作用:对通过 BeanFactory 创建的 bean 进行属性填充。
  这是AbstractAutowireCapableBeanFactory#populateBean 方法中的某一段代码: for (BeanPostProcessor bp : getBeanPostProcessors()) { 	if (bp instanceof InstantiationAwareBeanPostProcessor) { 		InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; 		PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); 		if (pvsToUse == null) { 			if (filteredPds == null) { 				filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); 			} 			pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); 			if (pvsToUse == null) { 				return; 			} 		} 		pvs = pvsToUse; 	} }
  我打出了所有要进行轮询校验的 BeanPostProcessor
  brokenComponent 中有两个bean:
  一个是通过@Resource 注解注入的,一个是通过@Autowire 进行注入的,奉劝各位同学千万不要两种混用啊!!! 2.4.1:CommonAnnotationBeanPostProcessor/**  * ...   *

The central element is the {@link javax.annotation.Resource} annotation * for annotation-driven injection of named beans, by default from the containing * Spring BeanFactory, with only {@code mappedName} references resolved in JNDI. * The {@link #setAlwaysUseJndiLookup "alwaysUseJndiLookup" flag} enforces JNDI lookups * equivalent to standard Java EE 5 resource injection for {@code name} references * and default names as well. The target beans can be simple POJOs, with no special * requirements other than the type having to match. * *

The JAX-WS {@link javax.xml.ws.WebServiceRef} annotation is supported too, * analogous to {@link javax.annotation.Resource} but with the capability of creating * specific JAX-WS service endpoints. This may either point to an explicitly defined * resource by name or operate on a locally specified JAX-WS service class. Finally, * this post-processor also supports the EJB 3 {@link javax.ejb.EJB} annotation, * analogous to {@link javax.annotation.Resource} as well, with the capability to * specify both a local bean name and a global JNDI name for fallback retrieval. * The target beans can be plain POJOs as well as EJB 3 Session Beans in this case. * ... */ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable { ... @Override public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs); try { metadata.inject(bean, beanName, pvs); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex); } return pvs; } }   通过翻译及反复debug验证,这个类将对某个bean中所有被 @Resource 注解修饰的属性进行填充。 2.4.2:AutowiredAnnotationBeanPostProcessor/** * {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation * that autowires annotated fields, setter methods and arbitrary config methods. * Such members to be injected are detected through a Java 5 annotation: by default, * Spring"s {@link Autowired @Autowired} and {@link Value @Value} annotations. * *

Also supports JSR-330"s {@link javax.inject.Inject @Inject} annotation, * if available, as a direct alternative to Spring"s own {@code @Autowired}. * ... * @see Autowired * @see Value */ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware { ... @Override public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); try { metadata.inject(bean, beanName, pvs); } catch (BeanCreationException ex) { throw ex; } catch (Throwable ex) { throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex); } return pvs; } }   这个类将对某个bean中所有被 @Autowire@Value 注解修饰的属性进行填充。 2.4.3:@Autowire VS @Resource   1:无论使用@Resource 还是 @Resource,都不影响bean的初始化顺序。   2:@Resource修饰的属性 要优先于 @Autowire修饰的属性 进行初始化。 2.5:报错流程1: getBean("brokenComponent") -> getSingleton("brokenComponent") -> beforeSingletonCreation("brokenComponent") -> createBean("brokenComponent") -> addSingletonFactory("brokenComponent") -> inject() -> 2: getBean("tubunComponent",TubunComponent.class) -> getSingleton("tubunComponent") -> beforeSingletonCreation("tubunComponent") -> 3:getBean("twConfig") -> getSingleton("twConfig") -> beforeSingletonCreation("twconfig") -> addSingletonFactory("twConfig") -> afterSingletonCreation("twConfig") 4:getBean("denpaComponent") -> getSingleton("denpaComponent") -> beforeSingletonCreation("denpaComponent") -> createBean("denpaComponent") -> addSingletonFactory("denpaComponent") -> inject() -> 5:getBean("tolenComponent") -> getSingleton("tolenComponent") -> beforeSingletonCreation("tolenComponent") -> createBean("tolenComponent") -> addSingletonFactory("tolenComponent") -> inject() -> 6:getBean("tubunComponent",TubunComponent.class) -> getSingleton("tubunComponent") -> beforeSingletonCreation("tubunComponent") -> 报错 7:afterSingletonCreation("tolenComponent") -> afterSingletonCreation("denpaComponent") -> afterSingletonCreation("tubunComponent") -> afterSingletonCreation("brokenComponent")   可以看到 tubunComponent 进行了两次 getSingleton,经过循环依赖检查的时候报错了。 2.6:错误流程分析归纳   1:Spring 容器先加载 brokenComponent 这个 bean。   2:brokenComponent依赖了tubunComponent(@Resource修饰),因此优先填充 tubunComponent,因此去初始化tubunComponent 这个bean,并将tubunComponent 存放在 DefaultSingletonBeanRegistry.singletonsCurrentlyInCreation 集合中。   3:tubunComponent依赖了depenComponent,因此去初始化depenComponent 这个bean,并将depenComponent 存放在 DefaultSingletonBeanRegistry.singletonsCurrentlyInCreation 集合中。   4:depenComponent依赖了tolenComponent,因此去初始化depenComponent 这个bean,并将tolenComponent 存放在 DefaultSingletonBeanRegistry.singletonsCurrentlyInCreation 集合中。   5:tolenComponent依赖了tubunComponent,因此去初始化tubunComponent 这个bean, 然而当将tubunComponent 存放在 DefaultSingletonBeanRegistry.singletonsCurrentlyInCreation 集合中时发现 tubunComponent 已经存在了,   从而判断这几个bean 产生了循环依赖并跑出异常。   beforeSingletonCreation(String beanName) 方法源码: /** * Callback before singleton creation. *

The default implementation register the singleton as currently in creation. * @param beanName the name of the singleton about to be created * @see #isSingletonCurrentlyInCreation */ protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } } 2.7:解决方式   1:使用@Lazy 修饰。   2:这其实是一个操作不当造成的问题,因为spring的三级缓存已经解决了set注入导致的循环依赖,而这几个bean并不是全部都是使用构造器注入。   在 brokeComponent 中使用@Autowired修饰了tolenComponent,又用@Resource 修饰了tubunComponent,   导致tubunComponent要优先于tolenComponent优先加载,而tolenComponent 又依赖了tubunComponent,因此报错。   我们只需要让tolenComponent 优先于 tubunComponent 优先加载就可以了。   实验证明:   1:@Resource 修饰 tolenComponent + @Resource 修饰 tubunComponent 的组合不会报错。   2:@Resource 修饰 tolenComponent + @Autowired 修饰 tubunComponent 的组合不会报错。   3:@Autowired 修饰 tolenComponent + @Autowired 修饰 tubunComponent 的组合不会报错。   偏偏使用了会报错的一种组合......


23,国乒遭日本组合双杀,爆冷再丢一冠!张本智和妹妹斩双冠北京时间12月7日,乒乓球世青赛继续进行,U19混双决赛中,国乒组合向鹏蒯曼23不敌日本组合筱塚大登木原美悠无缘冠军。U15混双决赛中,日本组合张本美和松岛辉空也成功夺冠。U19混女篮孙俪遭遇骨折wcba赛场出现恐怖的一个开放性骨折。wcba赛场出现严重受伤,江苏女篮松立被垫脚痛苦倒地,脚踝呈90度弯曲,从画面看非常严重,松力疼痛的喊叫响彻整个球场,真的太疼了。江苏主教练很理解别人,也要善待自己人与人之间最重要的是理解。你有你的缺点,我有我的,你说错话,我也有错的日子,所以我们要互相包容!然而,人与人之间,最难的是理解。你有你的想法,我有我的想法,我不懂你的难过,你不懂我澳洲直飞中国机票飙至9。3万!这里转机回国要21天,有人滞留第三国前言由于全球多国Omicron疫情爆发,搭乘回国航班的政策越收越紧,海外华人的回国之路变得越来越难。就在昨天不少买了机票的旅客发现,南航再度加码转机回国难度升级!01南航回国航班条雪上加霜,网传石宇奇被开除,谁来拯救国羽烂摊子雪上加霜,网传石宇奇被开除,谁来拯救国羽烂摊子。北京时间12月6日晚间,国内多家媒体爆出中国羽毛球男单选手因为此前汤姆斯杯半决赛比赛的不当言行遭到队内的禁赛。如果上述报道属实,那么开始走下坡路了?目前英超表现不佳的五位前锋,他们能找回状态吗英超联赛充满了有天赋的进攻球员,本赛季我们已经看到了一些前锋的疯狂表现。像萨拉赫克里斯蒂亚诺罗纳尔多瓦尔迪等球员都可以对对手造成毁灭性的威胁。没有什么比观看一场进攻和流畅的比赛更让在欧洲闪耀的韩国球员,亚洲一哥孙兴慜,登顶英超射手榜儿时的他说就算死也要踢球,长大后的他成为欧冠进球最多的亚洲球员之一,是世界级的球星,是球队进球的绝对主力。在别人谈起他和昔日的前辈朴智星时,他称是其带给了韩国足球运动员更多的机会。彻底废了!锡安体重达到310斤成NBA最重球员,如今跑动困难恐退役锡安威廉姆斯作为鹈鹕队的未来之星,他在禁区内的破坏力可以说是堪比奥尼尔,就连身体素质强悍的字母哥曾经也在篮下的对抗中吃亏被锡安直接从手中生抢过去而且还被放倒在地,可见他的力量有多么大反转,中超豪门老总李广益被抓前,曾狠批中国足球假赌黑横行北京时间12月8日,在昨天天津本地媒体爆料重大新闻称,原天津泰达总经理李广益被抓,目前正处于调查阶段,据说可能涉嫌严重违法,这一则新闻引爆了本地球迷圈。因为李广益在天津泰达工作长达双国家队的好处?姚明挖掘出56个原本不在视线中的球员一双国家队的初衷是好的。以往每次男篮公布12人大名单的时候,争议最大的一个点就是XXX和XXX怎么没有入选?他们打得那么好,而且正值职业生涯的巅峰期,已经入选的XXX论综合实力还不欧冠42!27岁前锋踢疯了,6场进10球力压莱万萨拉赫登顶射手榜北京时间12月8日凌晨4时,欧冠小组赛第6轮的一场比赛打响,阿贾克斯坐镇主场迎战葡萄牙体育队,最终阿贾克斯以42大胜对手,小组赛6战全胜昂首出线。最终的小组积分榜上,阿贾克斯豪取1
邹兆龙拳打李连杰,脚踢甄子丹,54岁终于与ampampquot常威ampampquot和解在内地在华人市场,你让我演反派无所谓,大家都是华人,但是在这里(国外),对不起无论你是黑的白的,我都不可能在这边演反派。这句话是香港演员邹兆龙在一段采访中所说的话,虽然他总是在各种歌手李健一个男人事业停滞不前,往往和他的伴侣有关我是山哥,多年专注情感专栏写作,聊情感人生,写生活感悟,感谢关注。山哥情感观点篇(山哥聊情感,图片来自网络)文庞凤山01hr提起歌手李健,大家耳熟能详的是他的那首脍炙人口的传奇,也2022最失望网剧陈浩民克演无脑片,钱小豪顶林正英名号拍烂片在以往,大家都喜欢去电影院看大片,但是这些年来受到疫情的冲击,很多的影院时不时关门,一些好作品也是接二连三的被推后延迟。看不了院线大片就只能看看网络大电影了,在2022年还是有着不中餐厅6首播将至,殷桃够美了,我却被另一位女嘉宾迷了眼中餐厅作为一档老牌的综艺节目,已经播出了5季,第一季的播放量就高达11亿,第二季也稳定在这样的水准,后续几季也有明显的提升,这与节目的热度越来越高有着分不开的关系。不过到了中餐厅第吴宣仪,爱好也要努力学习,一切都有希望作者李达源爱好也要认真对待,每个人都要把努力当成标配,马云说过,我们所有人的时间都是一样多的,而每个人之所以有了不一样的状态,就是每个人把自己有限的时间管理不同而已,这就是拉开距离2022年的华语乐坛怎么了?连网络热歌都不热了还记得前几年,每当盘点年度十大金曲十大热歌的时候,都会引来全网热议,因为上榜的歌曲,都是那些我们听到耳朵起茧却又一言难尽的网络神曲。大家就会感慨,华语乐坛是真的没落了!但今年大家发演艺圈影视演员出品人刘诗诗1731张美照相片合集(十七)一序言摘要演艺圈影视演员出品人刘诗诗1731张美照相片合集(十七),刘诗诗(原名刘诗施),出生于1987年3月10日,北京市人。欢迎朋友们关注留言互动沟通与交流!二演艺圈影视演员出涉案剧人民警察将袭,陆毅万茜领衔,冯雷杨立新戏骨云集凭借端正俊朗的外形,陆毅出演过很多深得人心的正面角色。最近几年,他最为人所知,担任主角的作品大概就是人民的名义了。这部剧中他正义凛然地反贪局局长形象十分光辉,从头到尾都带给观众踏实还是杨幂会玩!穿校服录节目演绎娇俏学生妹,35岁状态令人羡慕杨幂是娱乐圈里的当红一线女明星,顶着一张精致的脸蛋和完美的身材,每一次录节目或者参加品牌活动,都会成为全场瞩目的焦点。在密室大逃脱第四季的录制期间,杨幂的一举一动都备受关注,前段时父母爱情1件衣服德华葛美霞轮流穿,是剧组抠门还是别有隐情?父母爱情是2014年播出的一部剧,作为正午阳光来说,这部剧有着特殊的意义,而且如今该剧也成为了这个团队的招牌剧,我们可以看到如今在他们团队的很多作品中,都能出现这部剧的身影,这部剧著名歌手白雪人到中年再度翻红,离婚后收获完美的姐弟恋文格林妈妈白雪和丈夫原艺的相识,源于一次吵架。虽然当时两人水火不容,但事后他们却萌出了爱情,可谓不打不相识。在原艺的鼎力相助之下,白雪的事业又攀上了一个新的高峰,再度翻红。1975