疑难杂症之各种小坑合集

踩坑小合集

  • 前言
  • 正文
    • Spring注解相关
      • 一、@Async注解导致项目启动时提示循环注入错误
      • more and more 更多内容敬请期待,在闲暇之余都会记录上比较有趣的坑
      • !!!欢迎大家一起讨论哦,文章中有任何不对的地方,欢迎大家指正!!!

前言

工作生活中编码搬砖遇见的遇难杂症,大坑小坑记录,以备后续出现类似问题能快速找到解决方案

正文

开始填坑之旅吧,骚年们 项目都是基于SpringBoot开发的哟,所以问题的出现以及分析解决都是基于此的

Spring注解相关

一、@Async注解导致项目启动时提示循环注入错误

  • 总结解决方案 艾瑞巴蒂看过来 解决方案!解决方案!解决方案!在这里‍♂️‍♀️
    把这个放在最前面的原因是为了给没耐心或者急于先解决问题的小伙伴们能在第一时间搞定问题,然后再用空余的摸鱼时间来看看后续的分析过程
    1. 启动类中@ComponentScan(lazyInit = true)扫描注解增加懒加载配置,配置所有的Bean都使用懒加载的方式。(一般推荐,一劳永逸,妈妈再也不用担心我的项目出现循环注入启动失败的问题拉)
      PS:重点注意,该注解会使所有@Component注解都为懒加载,如果在该Bean中使用了@PostConstruct注解 那么在项目启动时该方法并不会执行!!!
    2. 最直接,最简单,最粗暴的方案:将@Async注解取消,使用线程池异步执行方法内代码段 。(一般推荐,感觉不是那么优美的解决方式)
    3. 将所有导致循环注入的bean都加上@Lazy注解。(一般般推荐,在项目注入的Bean比较少的情况下能快速解决,但是在我们公司现在的项目中高达几百个Service注入,各种前辈们的循环注入,怕是加到吐血都不能搞定啊)
    4. 重新整理各个Bean之间的关系,调整为顺序加载,Bean之间的关系尽量简化。(不推荐。我只能说这个是个理论解决办法,现实中只有五个字能描述,几乎不可能!在自己和前辈们的经验下,告诫一下各位新猴子们,能正常运行的旧代码和逻辑,能不动就尽量不动,对这句话深有体会的都是经历过血与泪的教训的勇士)
  • 问题描述
    1. 项目启动时报错,错误描述大致:org.springframework.beans.factory.BeanCurrentlyInCreationException:Error creating bean with name ‘solrService’: Bean with name ‘solrService’ has been injected into other beans …in its raw version as part of a circular reference…This is often the result of over-eager type matching - consider using ‘getBeanNamesOfType’ with the ‘allowEagerInit’ flag turned off, for example.
  • 分析思路
    1. 注意异常中关键错误描述circular reference,意思为循环引用
    2. 当发现是循环引用问题后,第一反应是增加 @Lazy 注解,于是根据启动初始化错误信息,将提示的几个service中引用类上加上@Lazy注解,再次启动,发现又有新的类初始化失败,异常描述也是循环引用,再次添加懒加载注解启动,依然启动失败,异常日志中初始化错误的类又改为了其他的,这时我觉得可能问题没这么简单,因为这个项目中service有上百个,循环引用的特别多,特别错综复杂
    3. 当发现单纯的按照错误日志增加@Lazy注解时,无法快速的解决问题后,我怀疑可能不是单纯的新增几个循环引用的bean,
    4. 因为这个项目在上午的时候测试环境还能正常启动调试,在下午突然就无法启动了,我怀疑是上午同事提交的什么代码导致的该问题出现,于是我在本地按git提交记录一层层回退启动,定位到了导致无法启动的提交记录
    5. 就是该段代码导致启动出现循环依注入问题,在将@Async注解注释后,项目即可正常启动
      疑难杂症之各种小坑合集_第1张图片
    6. 于是先用最粗暴的方式解决掉,让测试环境能正常启动使用,取消@Async注解,使用线程池异步调用,具体代码见图
      疑难杂症之各种小坑合集_第2张图片
  • PS
    • 既然遇见这个问题,就查询一下资料搞清楚异常的根本原因和尽可能多的解决方案吧,让以后这一方面的坑都被踏平
    • 于是就有了下面的内容
  • 知识点延申
    • Spring中Bean的加载过程
      参考文档:https://blog.csdn.net/lianhuazy167/article/details/66967673
      1. bean的实例化过程:create bean → cache bean → inject element → inject element → inject element … … → finish
      2. 非循环依赖场景:A依赖B,先创建A
        实例化过程为:create A → cache A → create B → cache B → finish B → inject B to A → finish A。
        PS:被依赖对象先finish,即B先于A实例化完成
      3. 循环依赖场景:A依赖B,B依赖A,先创建A
        实例化过程为:create A → cache A → create B → cache B → inject A to B → finish B → inject B to A → finish A。
        PS:spring允许eagerly cached instance注入到其他bean中,eagerly cached instance 指已缓存但未finish的bean
      4. 注意!!!:在SpringBoot项目中,Spring的Bean容器默认都是使用的单例模式,在该模式下Bean的创建才会Cache,并且循环注入才会被支持
    • 为什么加入@Async注解会导致初始化的时候提示循环注入
      1. 注意启动异常日志中的这段话“Bean with name ‘solrService’ has been injected into other beans”,该Bean在其他的Bean中已经被注入了
      2. 抽象模拟循环注入并且存在@Async注解时各个Bean的实例化过程
        抽象循环注入情况:A依赖B、C依赖B,B依赖C,并且B实现类的方法上存在@async注解
        注入步骤
        • A开始create,发现B未实例化,于是先cache A
        • B开始create,发现C未实例化,于是先cache B1
        • C开始create,发现B已实例化,取出cache的B1,注入C中,C finish
        • B中存在@Async注解,Spring中异步注解实现也是实现该类的代理对象,则 B2 finish
        • B2注入到A中时,发现B的实例B1已经注入到C中,但是并未使用最终代理B2,所以抛出异常has been injected into other beans

more and more 更多内容敬请期待,在闲暇之余都会记录上比较有趣的坑

!!!欢迎大家一起讨论哦,文章中有任何不对的地方,欢迎大家指正!!!

你可能感兴趣的:(经验总结,spring,java,spring,boot)