221

在将由 Spring 连接的类 中使用@Autowired的优缺点是什么?

澄清一下,我说的是@Autowired注释,而不是 XML 中的自动装配。

我可能只是不明白,但对我来说,这几乎像是一种反模式——你的类开始意识到它们与 DI 框架相关联,而不仅仅是 POJO。也许我喜欢惩罚,但我喜欢 bean 的外部 XML 配置,而且我喜欢有明确的连线,所以我确切地知道什么连线在哪里。

4

9 回答 9

255

很长一段时间以来,我认为拥有像我们都使用的 xml 文件一样的“集中式、声明式配置”是有价值的。然后我意识到文件中的大部分内容都不是配置- 在开发之后的任何地方都没有改变过,永远。然后我意识到“集中式”只在非常小的系统中有价值——只有在小系统中,你才能将配置文件作为一个整体来理解。当相同的“布线”大多被代码中的依赖项复制时,理解整个布线的真正价值是什么?所以我唯一保留的是元数据(注释),它仍然是一种声明性的。这些在运行时永远不会改变,而且永远不会有人会即时更改的“配置”数据 - 所以我认为将其保存在代码中很好。

我尽可能多地使用全自动接线。我喜欢它。除非受到枪口威胁,否则我不会回到旧式春天。我更喜欢完全的原因@Autowired随着时间的推移而改变。

现在我认为使用自动装配的最重要原因是系统中需要跟踪的抽象更少。“bean name”实际上已经消失了。事实证明,bean 名称仅因 xml 而存在。因此,一整层抽象间接(您将 bean-name “foo” 连接到 bean “bar” 的地方)消失了。现在我将“Foo”接口直接连接到我的 bean 中,并由运行时配置文件选择实现。这允许我在跟踪依赖项和实现时使用代码。当我在我的代码中看到一个自动装配的依赖项时,我可以在我的 IDE 中按下“转到实现”键,然后出现已知实现的列表。在大多数情况下,只有一个实现,我直接进入课堂。能'正在使用什么实现(我声称相反的情况更接近 xml 布线的真相 - 有趣的是你的观点如何变化!)

现在你可以说它只是一个非常简单的层,但是我们添加到系统中的每一层抽象都会增加复杂性。我真的不认为 xml 为我使用过的任何系统增加了任何真正的价值。

我曾经使用过的大多数系统都只有一种生产运行时环境配置。测试等可能还有其他配置。

我想说完全自动装配是 spring 的 ruby​​-on-rails:它包含这样一个概念,即大多数用例都遵循一种正常和常见的使用模式。使用 XML 配置,您可以使用很多一致/不一致的配置,这些配置可能/可能不是预期的。我已经看到很多 xml 配置因不一致而过度使用 - 它是否与代码一起重构?没想到。这些变化是有原因的吗?通常不会。

我们在配置中几乎不使用限定符,而是找到了解决这些情况的其他方法。这是我们遇到的一个明显的“缺点”:我们稍微改变了编码方式,使其与自动装配交互更顺畅:客户存储库不再实现通用Repository<Customer>接口,但我们创建了一个CustomerRepository扩展接口Repository<Customer>。有时在子类化方面也有一两个技巧。但它通常只是将我们指向更强大的打字方向,我发现这几乎总是一个更好的解决方案。

但是,是的,您正在绑定一种特定风格的 DI,而这种风格主要是 spring 所做的。我们甚至不再为依赖项创建公共设置器(所以你可以说我们在封装/信息隐藏部门是 +1 的)我们的系统中仍然有一些 xml,但 xml 基本上包含异常。完全自动装配与 xml 很好地集成。

我们现在唯一需要的是将@Component,@Autowired其余部分包含在 JSR 中(如JSR-250),因此我们不必与 spring 绑定。这就是过去发生的事情的方式(这些java.util.concurrent事情浮现在脑海中),所以如果这种情况再次发生,我不会完全感到惊讶。

于 2009-03-11T14:30:36.980 回答
26

对我来说,这是我喜欢/不喜欢 Spring 和自动布线的地方。

优点:

  • 自动装配摆脱了讨厌的 XML 配置。
  • 更容易使用注释,它允许您直接使用字段、setter 方法或构造函数进行注入。还允许您注释和“限定”注入的 bean。

缺点:

  • 使用自动装配和注释使您依赖于 Spring 库,与 XML 配置一样,您可以选择在有或没有 Spring 的情况下运行。就像你说的,你被绑定到一个 DI 框架。
  • 同时我喜欢能够“限定”bean,对我来说这使得代码非常混乱。如果您需要在多个地方注入同一个 bean,我看到相同的字符串名称到处重复。对我来说,这似乎有可能出错。

我已经开始几乎完全在工作中使用自动连接,因为无论如何我们都非常依赖 Spring 集成,以至于依赖问题没有实际意义。我参与了一个 Spring MVC 项目,该项目广泛使用了自动装配,并且有点难以理解。

我认为自动装配是一种后天的习惯,一旦你习惯了它,你就会意识到它是多么强大、容易,而且比 XML 配置更容易使用。

于 2009-03-11T03:02:15.937 回答
15

在我们的大项目中,我们正在从 @Autowire 切换回 XML 配置。问题是引导性能非常低。自动装配扫描器从自动装配搜索类路径加载所有类,因此,在 Spring 初始化期间急切地加载了许多类。

于 2010-11-30T13:20:45.167 回答
6

关于切换环境的讨论很少。我从事的大多数项目都是根据我们正在处理的环境注入依赖项是一个真正的问题。使用 xml 配置,使用 Spring EL 非常简单,而且我不知道有任何带有注释的好解决方案。我刚刚想出了一个:

    @Value("#{${env} == "production" ? realService : dummyService}")
    private SomeService service;

它应该可以工作,但恕我直言,这不是一个好的解决方案。

于 2012-11-20T10:27:35.720 回答
4

我已切换到@Autowire。维护除小型项目以外的任何东西的 XML 配置本身就成为一项任务,并且理解力迅速下降。

IntelliJ 为 Spring 注释提供了良好(不完美)的支持。

于 2009-07-09T13:02:30.740 回答
3

我对这个主题的看法是,xml 配置会降低代码的清晰度,尤其是在大型系统中。

@Component 之类的注解让事情变得更糟。它引导开发人员使对象可变,因为依赖关系不能再成为最终的,因为需要提供默认构造函数。依赖项要么通过公共设置器注入,要么通过@Autowired 不受控制。[更糟糕的依赖注入被实例化其依赖的类所破坏,我仍然在新编写的代码中看到这一点!]。不受控制的意思是,在大型系统中,当该类型的多个实现(或子级)可用时,要了解哪些实现是@Autowired 会更加复杂,这使得调查错误变得更加困难。这也意味着,假设您有一个用于测试环境的配置文件和另一个用于生产的配置文件,

我坚持声明我的配置类的中间立场,(使用@Configuration的基于java的Spring配置)

我在配置类中明确声明了我的所有 bean。我只在配置类中使用@Autowired,目的是将Spring的依赖限制在配置类中

@Configuration 驻留在特定的包中,这是 spring 扫描运行的唯一位置。(这大大加快了大型项目的启动时间)

我努力使我的所有类不可变,尤其是数据对象、JPA、Hibernate 和 Spring,以及许多序列化库似乎破坏了这一点。我避开任何强迫我提供 setter 或从我的属性声明中删除 final 关键字的东西。

减少创建对象后更改对象的可能性,大大减少了大型系统中的错误,并减少了在存在错误时发现错误的时间。

它似乎也迫使开发人员更好地设计系统不同部分之间的交互。问题和错误变得越来越多的编译错误,从而减少浪费的时间并提高生产力。

于 2011-02-14T17:29:32.697 回答
1

以下是一些
经验

  • 使配置更容易,因为我们可以使用 @Autowire 注释
  • 不想使用setter方法,所以类会更干净

缺点

  • 即使我们使用 DI,也与 xml 文件紧密耦合
  • 很难找到实现(但如果你使用像 intellij 这样的好 ide,你肯定可以摆脱这个)

根据我的个人经验,我没有太多使用@AutoWire 注释,而是在测试用例中使用。

于 2012-11-06T14:45:18.993 回答
1

我真的很喜欢用注释而不是 XML 来编写。根据 Spring 手册和最新版本,XML 和 Annotation 达到了相同的结果。

这是我的清单

临:

  • 从 xml 中删除无用的行
  • 简化调试代码:当你打开一个类时,你可以阅读你在类中的内容
  • 开发速度更快,400 行或更多行 XML 的项目是否可读?

缺点:

  • 不是标准的Java实现,但是你可以切换到使用@Inject,这是一个Java标准Api,所以bean仍然是一个Pojo
  • 您不能简单地在任何地方使用,数据库连接 e 等等,但这只是一种意见,我更喜欢有一个可以读取所有配置的地方。
于 2013-02-03T11:49:36.100 回答
0

据我了解,@Autowired 在引用接口参考并使用其覆盖功能时最好使用,但我只发现这个问题是它有时在运行时分配为 null。

于 2017-02-23T11:21:21.803 回答