V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
linuxsteam
V2EX  ›  Java

Spring 出现循环依赖 (Is there an unresolvable circular reference?) 哪种解决方式最好?

  •  
  •   linuxsteam · 2020-05-21 08:19:33 +08:00 · 5766 次点击
    这是一个创建于 1645 天前的主题,其中的信息可能已经有所发展或是发生改变。

    问题出现场景: 本地启动不会报错,服务器上启动会报错 Error creating bean with name ‘passwordEncoder’: Requested bean is currently in creation: Is there an unresolvable circular reference?

    • 目前小弟只成功使用了一个不能称之为办法的解决办法,就是不交给 Spring,直接 new 一个对象.此贴想抛砖引玉 学习大家的解决办法。

    图 1 图 2 图 3

    请问

    • 问题 1SpringIOC 是不是通过 @ComponentScan 去把扫描到的相关带有注解的类注入到 Bean 中吗?
    • 问题 2继续上个问题(见图 2 ),注入顺序我说的是否正确?
      1. 先将 WebSscurityConfig 注入到 Bean 中
      2. 然后再将需要的 CustomAuth....注入到 Bean
      3. 最后将 passwordEncoder 注入到 Bean
    • 扣题如果我想解决上述代码导致的循环依赖,我并不想使用 new 一个 PasswordEncoder 的方式(见图 3 )解决循环依赖,有没有更优雅的办法?
      1. 个人尝试了 @Postconstruct (见图 2 ) 29 行 /46 行插入这个注释 启动项目还是报错
      2. 还没想出来...
    20 条回复    2020-05-22 13:02:25 +08:00
    SoulSleep
        1
    SoulSleep  
       2020-05-21 08:31:46 +08:00
    现在版本的 Spring 不会在日志里打印出你循环依赖的三个类吗?

    如果你本地启动没问题,那大概就是加载顺序的问题了

    循环依赖我感觉有两种办法:


    1.检查你的引用是否有 jar 冲突,jar 的加载顺序改变了 bean 初始化的顺序
    2.使用 @DependOn 去指定 bean 加载顺序
    Dachunlv
        2
    Dachunlv  
       2020-05-21 08:36:42 +08:00   ❤️ 1
    出现循环依赖大多数情况说明逻辑设计上就出了问题,可以尝试调整设计本身,否则治标不治本。比如创建中间代理 Bean ?
    luckyrayyy
        3
    luckyrayyy  
       2020-05-21 08:39:01 +08:00
    懒加载一个
    luckyrayyy
        4
    luckyrayyy  
       2020-05-21 08:41:53 +08:00
    或者你只从一个地方注入,另一个地方把已经注入的 bean 以构造器参数 /setter 的方式传过去
    xuanbg
        5
    xuanbg  
       2020-05-21 08:43:38 +08:00
    循环依赖就是典型的「代码写错了地方」。解决这个问题也很简单,把写错地方的代码挪到正确的地方就行。如楼主的例子,就是把 passwordEncode 这个方法从 WebSecurityConfig 拿出来单独一个类就行了
    aaronysj
        6
    aaronysj  
       2020-05-21 08:54:23 +08:00
    建议做法是把这种 @Bean 的注入,统一到一个单独的 Config 配置类中。
    quarria
        7
    quarria  
       2020-05-21 08:57:17 +08:00
    我也出现过这问题,原来 springboot2.0.3 的时候一点问题没有,升级到 2.2.6 就出现了这问题。第一种方法是在互相能循环调用的类上加懒加载的注解。第二种方法是实现 BeanFactoryPostProcessor 这个类中的 postProcessBeanFactory 方法。方法内写((AbstractAutowireCapableBeanFactory) beanFactory).setAllowRawInjectionDespiteWrapping(true); 这样就可以启动不报错了,但治标不治本,最终还是优化代码,尽量解耦,不出现循环调用的问题。
    xiaofan2
        8
    xiaofan2  
       2020-05-21 09:02:16 +08:00
    setter 注入能产生循环依赖吗? 你的 PasswordEncoder 是自建的还是什么
    aragakiyuii
        9
    aragakiyuii  
       2020-05-21 09:02:45 +08:00 via Android
    再包一层

    官方推荐用构造函数注入而非注解注入
    yRebelHero
        10
    yRebelHero  
       2020-05-21 09:09:53 +08:00
    试试用 @Lazy ?不过一般这样就是设计出问题了。
    linuxsteam
        11
    linuxsteam  
    OP
       2020-05-21 09:10:16 +08:00
    @SoulSleep 谢谢回答。
    有提示三个类 我就是改了其中一个类为 new 对象的形式才解决的。

    一会大家的方法我挨个试试,再次感谢
    Foxkeh
        12
    Foxkeh  
       2020-05-21 09:12:15 +08:00
    szuwl
        13
    szuwl  
       2020-05-21 09:13:14 +08:00
    1. 懒加载
    2. 重构(更改设计)
    linuxsteam
        14
    linuxsteam  
    OP
       2020-05-21 09:14:48 +08:00
    @quarria 是的。你的那种做法,我在百度搜到了。但是无奈还得加代码(那个实现的类我还不了解,就放弃了)
    linuxsteam
        15
    linuxsteam  
    OP
       2020-05-21 09:19:52 +08:00
    @xiaofan2 springsecurity 自带的。
    Jrue0011
        16
    Jrue0011  
       2020-05-21 09:43:17 +08:00
    应该是不在 WebSecurityConfig 里注册 passwordEncoder,另外找个地方注册就行
    cco
        17
    cco  
       2020-05-21 10:00:09 +08:00
    构造器注入就可以。
    pomelotea2009
        18
    pomelotea2009  
       2020-05-21 12:53:05 +08:00 via Android
    @Dachunlv 赞同,最简单的比如服务 A&B 循环依赖,你可以把服务 B 里对服务 A 的调用,挪到控制器里去做,在控制器里调用服务 A 之后,结果传参调用服务 B,原则上服务 A 和 B 也应该尽量隔离,除了一些小的工具服务
    Chinsung
        19
    Chinsung  
       2020-05-21 17:43:46 +08:00
    之前遇到过,首先逻辑最好理清楚,确实会有这样的问题,本地可以,服务器不行,如果实在不想大调整,或者 DependsOn 注解解决不了问题,可以把报错的那个类的 spring 配置类的包结构深度来改变顺序,我之前就是这么解决的
    linuxsteam
        20
    linuxsteam  
    OP
       2020-05-22 13:02:25 +08:00
    @Chinsung 那就是说 浅的优先注入呗? 如果这样就行,这个适合懒人啊
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   978 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 20:34 · PVG 04:34 · LAX 12:34 · JFK 15:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.