为什么Spring不支持直接字段依赖注入(自动装配除外)?

时间:2011-03-25 13:32:19

标签: java spring dependency-injection

我对直接场依赖注入感兴趣。传统上,Spring支持构造函数注入(为构造函数提供参数)和基于setter的注入(在调用时调用setter)。

但是,Spring也能够直接注入场景(在没有setter方法的情况下设置对象的成员字段),通过使用@Autowired注释字段来证明。自动装配仅限于“bean”,因此无法注入原始值(虽然这可以通过创建类“java.lang.String”的bean来规避 - 这可行,但具有正常的自动装配警告。)除了这样,Spring支持@Value直接将值设置为属性等的成员字段。

然而,Spring不允许将属性直接设置为成员字段(没有自动装配)。

我的问题是:为什么?

显然有能力这样做,为什么不呢?是否有任何大的负面副作用阻止这种情况?或者这种能力是否有限,只有自动装配才有意义?它是否需要比调用setter更大的黑客攻击?

请注意,我不想讨论一般的setter和getter的相对优点,只是Spring做出这个选择的原因。

3 个答案:

答案 0 :(得分:10)

我想我自己找到了答案。我转到Spring源代码,看看这些功能是如何实现的。这是我发现的:

通过XML设置属性可能是Spring最古老的部分,它非常依赖于“java.beans”类来进行内省,属性枚举等。显然,那些根本不支持字段内省。最重要的是类型转换机制,它确定如何将属性值转换为相关属性的合适值。这里没有整齐的可分离部分。

所有@Autowired等东西都是在BeanPostProcessor中实现的,它有自己的类型匹配机制,与类型转换无关。这也是它只注入豆类的原因。 @Value也是如此,它只是当场解决的东西,与属性无关。

因此,特别是为属性添加字段注入支持并不是一项简单的工程工作,因为执行其中一个或另一个的代码部分几乎完全是分开的。

这并不完全回答“为什么?”,但我认为这是一个更引人注目的解释,为什么Spring没有添加直接场依赖注入,而不是我听过的其他解释。除非他们有一些基本的东西(我怀疑,考虑到他们想要允许配置现有的第三方类,而不仅仅是JavaBeans),那么只需要通过工程努力来获得功能。

答案 1 :(得分:9)

@Autowired注释使用反射来访问私有字段(请参阅this related question)。我可以看到为什么它没有在Spring配置文件中使用的三件事。

  1. 由于配置是通过bean属性(getter和setter)发生的,所以你无法真正告诉 - 如果你想要的话,可能存在 - 调用setValue或设置成员值。
  2. 打破了封装。您的Spring配置没有理由了解私有成员变量。使用注释即可,因为它已经在源代码中。
  3. 安全问题。限制性更强的安全管理器可能不允许通过反射访问私有字段。

答案 2 :(得分:1)

通过JSR-250 @Resource注释(在Spring 3.0 +中)支持

我个人更喜欢这种注射器,并且在考虑构造器注射时对此有不同的感受。以下是我对FWIW的考虑因素:

1)构造函数注入是一种很好的方式来自我记录你的bean依赖项(pro)但是会产生很多DRY违规:(a)私有字段,(b)构造函数参数,(c) )构造函数代码从参数设置字段,(d)bean配置中的附加代码(在@Configuration类或xml中)。这只是为了一些封装纯度而导致很多干扰,我甚至都不关心。这几乎不违反封装 - 但它确实对某些注入容器产生了很大的依赖性,该注入容器尊重JSR-250注释(参见下文)

2)创建对符合JSR-250的容器的依赖。对此我五味杂陈。当我第一次听说@Resource时,我把它写下来说它会让我的系统更难测试。但是,无论如何,我最终在测试中使用了spring。我仍然可以像我一样使用模拟豆,所以它从来都不是一个问题。问题是在测试之外,什么时候你真的想重用它。在我看来,如果你正在设计系统以利用容器,那么就拥抱它并使用它。干燥的违规行为是否真的值得在容器内运行的灵活性?至少使用JSR-250注释,您可以在任何JEE6环境中运行并按照您的需要进行注入。

3)如果你在容器之外实例化一个调试方案,可以创建一些不那么好的调试方案:即你将得到空指针异常而不是好东西。这是一种权衡。我个人认为它并不可怕 - 我的意思是如果你在@Resource的线上获得NPE,那么你很快意识到它没有被注入。