Spring的Bean管理,一直是整个体系中津津乐道的东西。尤其是Bean的循环依赖,更是很多面试官最喜欢考察的2B知识点之一。
但事实上,项目中存在Bean的循环依赖,是代码质量低下的表现。多数人寄希望于框架层来给擦屁股,造成了整个代码的设计越来越糟,最后用一些奇技淫巧来填补犯下的错误。
还好,SpringBoot终于受不了这种滥用,默认把循环依赖给禁用了!
从2.6版本开始,如果你的项目里还存在循环依赖,SpringBoot将拒绝启动!
[图片上传失败...(image-f43b52-1652425705349)]
验证代码小片段
为了验证这个功能,我们只需要两段小代码。
CircularDependencyA.java
<pre class="prettyprint hljs less" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">@Component
@RequiredArgsConstructor
public class CircularDependencyA {
private final CircularDependencyB circB;
}</pre>
CircularDependencyB.java
<pre class="prettyprint hljs less" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">@Component
@RequiredArgsConstructor
public class CircularDependencyB {
private final CircularDependencyA circA;
}</pre>
RequiredArgsConstructor注解,是lombok包里面的,用来实现简单的构造器注入。不出所料,当我们启动代码的时候,报错了~~
报错如下:
<pre class="prettyprint hljs vbnet" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| circularDependencyA defined in file [cir/CircularDependencyA.class]
↑ ↓
| circularDependencyB defined in file [cir/CircularDependencyB.class]
└─────┘
Action:
Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.</pre>
当然,有些鸟人已经玩大了,循环依赖到处都是,改代码变的越来越不现实。那你还可以通过在yaml里配置参数来临时开启循环依赖。
<pre class="prettyprint hljs lua" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">spring.main.allow-circular-references=true</pre>
看来SpringBoot对恶势力的容忍能力还是不够坚决啊!
绕过SpringBoot这个拦截的方法不止一种,比如使用@Lazy注解进行延迟初始化。但这些都是治标不治本,辜负了SpringBoot的一片苦心。
做对的事其实,我们一直把代码往下找下去,会发现这个开关,其实是Spring的功能。
<pre class="prettyprint hljs vbnet" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">AbstractAutowireCapableBeanFactory#allowCircularReferences
/** Whether to automatically try to resolve circular references between beans. */
private boolean allowCircularReferences = true;</pre>
很长一段时间,SpringBoot这个值都是默认为true的。但这种纵容造成了大批低质量的代码产生,以至于新员工一直在给老员工埋坑。
把这个值默认设置为false,是坚持做对的事情。起码,在工程师编写出质量不高的代码时,能够知道他自己在做什么,而不是把隐患一步步的推迟,任代码腐败。
不得不为SpringBoot点个赞。真棒!
网友评论