Spring框架中有三种注入变量:
- 基于二传手的注射
- 基于构造函数的注入
- 基于现场的注入
这些机制中的每一种都有优点和缺点,并且不仅只有一种正确的方法。 例如现场注入:
@Autowired
private FooBean fooBean;
在生产代码中使用它通常不是最好的主意,主要是因为它使我们的bean无法在不启动Spring上下文或不使用反射hack的情况下进行测试。 另一方面,它几乎不需要其他代码,并且可以在集成测试中使用-绝对不会独立实例化。 在我看来,这是基于现场注射的唯一情况。
现在,让我们关注两个主要变体。 在Spring文档中,我们可以读到
…将构造函数参数用于强制性依赖项并将设置器用于可选的依赖项是一个很好的经验法则。
同样在参考Spring到3.1的文档中 ,我们可以找到一个句子
Spring团队通常提倡setter注入,因为大量的构造函数参数可能变得笨拙,尤其是当属性是可选的时。
这种情况在文档中已更改为第四版,其中指出:
Spring团队通常提倡构造函数注入,因为它使人们能够将应用程序组件实现为不可变对象,并确保所需的依赖项不为null。
尤其是在版本4.0之前的人们使用基于构造函数的注入方式(其中有些“纯粹主义者”(也可以在本文档中找到))时, 这非常酷:)请注意,在第四个框架发布之前,这种注入方式存在很大的问题–方面要求使用默认构造函数。 现在仍然存在基于构造函数的注入的“缺点”:它不允许循环依赖。 我特意在双引号中添加了缺陷,因为对我而言,这是该机制的巨大优势:)文档中还有另外一句话:
通常建议不要在bean之间使用循环引用。
但为什么? 如果我们的应用程序中有循环引用,该怎么办? 我不想写关于应用程序设计的文章,因为几乎总是可以重构我们的代码并将有问题的逻辑委托给第三个bean。 有两个重大而不幸的“沉默”问题。
第一个陷阱
调用ListableBeanFactory.getBeansOfType()方法时,不能确定将返回哪些Bean。 让我们看一下DefaultListableBeanFactory类的代码:
if (isCurrentlyInCreation(bce.getBeanName())) {if (this.logger.isDebugEnabled()) {this.logger.debug("Ignoring match to currently created bean '"+ beanName + "': " + ex.getMessage());}// ...continue;
}
如您所见,如果您不使用DEBUG日志记录级别,那么将有零个信息表明Spring在解析过程中跳过了特定的bean。 如果您想获得所有事件处理程序,那就太麻烦了:)
第二个陷阱
第二个问题涉及AOP。 如果要在bean上使用方面,请确保它不涉及循环引用-否则Spring将创建bean的两个实例–一个没有方面,另一个具有适当方面。 当然仍然没有任何信息。 惊讶吗
对我来说, 停止在我们的应用程序中使用循环依赖就足够了(特别是与此相关的行为可能更有趣)。
请勿使用循环依赖!
但是,我们该如何摆脱困境呢? 当然,您可以使用基于构造函数的注入:)但是,如果您有大量的应用程序,那么花很多时间重写所有类以使用构造函数而不是setter并不是最好的主意。 幸运的是,我有个好消息– AbstractRefreshableApplicationContext类中的allowCircularReferences字段。 只需添加一行到应用程序上下文创建(所描述的方式在这个岗位 )
AnnotationConfigWebApplicationContext applicationContext =new AnnotationConfigWebApplicationContext();
applicationContext.setAllowCircularReferences(false);
// rest of context initialization
最后,为了使您心情愉快,我从DefaultListableBeanFactory粘贴了另一个代码片段:
catch (NoSuchBeanDefinitionException ex) {// Shouldn't happen - probably a result of circular reference resolution...if (logger.isDebugEnabled()) {logger.debug("Failed to check manually registered singleton with name '"+ beanName + "'", ex);}
}
祝你今天愉快! :)
翻译自: https://www.javacodegeeks.com/2015/01/dependency-injection-pitfalls-in-spring.html