Spring @Autowired 用法
在由 Spring 连接的类中使用 @Autowired 的优点和缺点是什么?
澄清一下,我具体讨论的是 @Autowired 注释,而不是 XML 中的自动装配。
我可能只是不明白它,但对我来说,这几乎像是一种反模式 - 你的类开始意识到它们与 DI 框架相关,而不仅仅是 POJO。 也许我是一个贪图惩罚的人,但我喜欢为 bean 提供外部 XML 配置,并且我喜欢有明确的连接,所以我确切地知道什么连接在哪里。
What are the pros and cons of using @Autowired in a class that will be wired up by Spring?
Just to clarify, I'm talking specifically about the @Autowired annotation, not auto-wiring in XML.
I probably just don't understand it, but to me it almost seems like an anti-pattern - your classes start to become aware that they are tied to a DI framework, rather than just being POJOs. Maybe I'm a glutton for punishment, but I like having the external XML config for beans, and I like to have explicit wirings, so I know exactly what is wired where.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

发布评论
评论(9)
对我来说,这是我喜欢/不喜欢 Spring 和自动装配的地方。
优点:
- 自动装配消除了讨厌的 XML 配置。
- 使用注释更容易,它允许您直接使用字段、setter 方法或构造函数进行注入。 还允许您注释和“限定”注入的 bean。
缺点:
- 使用自动装配和注释会使您依赖于 Spring 库,而使用 XML 配置时您可以选择使用或不使用 Spring 来运行。 正如您所说,您会与 DI 框架联系在一起。
- 同时我喜欢能够“限定”bean,对我来说这使得代码非常混乱。 如果您需要在多个位置注入相同的 bean,我已经看到相同的字符串名称到处重复。 对我来说,这似乎有可能出错。
我开始在工作中几乎完全使用自动装配,因为无论如何我们都非常依赖 Spring 集成,以至于依赖问题没有实际意义。 我参与了一个 Spring MVC 项目,该项目广泛使用了自动装配,但有点难以理解。
我认为自动装配是一种后天习得的习惯,一旦你习惯了它,你就会意识到它是多么强大、简单,而且比 XML 配置更容易使用。
我对此主题的看法是,xml 配置会降低代码的清晰度,尤其是在大型系统中。
像 @Component 这样的注释会让事情变得更糟。 它引导开发人员使对象可变,因为考虑到需要提供默认构造函数,依赖项不能再成为最终的。 依赖关系需要通过公共 setter 注入,或者通过 @Autowired 不受控制。 [更糟糕的是,依赖注入会受到实例化其依赖项的类的影响,我仍然在新编写的代码中看到这一点!]。 我所说的不受控制是指,在大型系统中,当该类型的多个实现(或子级)可用时,需要更多地了解哪些实现是@Autowired,这种复杂性使得调查错误变得更加困难。 这也意味着,假设您有一个用于测试环境的配置文件和另一个用于生产环境的配置文件,那么您的生产错误只会在最严重的情况下发生 - 在生产中,而不是能够在测试环境中发现错误,甚至更好的是在编译时间!
我坚持声明我的配置类的中间立场,(使用@Configuration的基于java的Spring配置)
我在配置类中显式声明我的所有bean。 我只在配置类中使用@Autowired,目的是限制Spring对配置类的依赖。
@Configuration驻留在特定的包中,这是Spring扫描运行的唯一位置。 (这大大加快了大型项目的启动时间)
我努力使所有类都是不可变的,尤其是数据对象、JPA、Hibernate 和 Spring,以及许多序列化库似乎破坏了这一点。 我会避开任何迫使我提供设置器的东西,或者从我的属性声明中删除 Final 关键字。
减少对象创建后更改的可能性,大大减少大型系统中的错误,并减少发现错误时的时间。
这似乎也迫使开发人员更好地设计系统不同部分之间的交互。 问题和错误变得越来越多的编译错误,这减少了浪费的时间并提高了生产力。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
很长一段时间以来,我相信拥有“集中式、声明性、配置”(就像我们过去都使用的 xml 文件)是有价值的。 然后我意识到文件中的大部分内容都不是配置 - 它在开发后从未在任何地方发生过更改。 然后我意识到“集中式”仅在相当小的系统中才有价值 - 只有在小型系统中,您才能够理解配置文件作为一个整体。 当相同的“接线”大部分由代码中的依赖项重复时,理解整个接线的真正价值是什么? 所以我唯一保留的是元数据(注释),它仍然是一种声明性的。 这些永远在运行时改变,并且它们永远是某人会即时更改的“配置”数据 - 所以我认为将其保留在代码中是很好的。
我尽可能使用全自动接线。 我喜欢它。 除非受到枪口威胁,否则我不会回到旧式春天。 随着时间的推移,我完全喜欢
@Autowired
的原因已经发生了变化。现在我认为使用自动装配的最重要原因是系统中需要跟踪的抽象少了。 “bean 名称”实际上已经消失了。 事实证明,bean 名称仅因 xml 而存在。 因此,完整的抽象间接层(您将 bean 名称“foo”连接到 bean“bar”)消失了。 现在,我将“Foo”接口直接连接到我的 bean 中,并通过运行时配置文件选择实现。 这使我能够在跟踪依赖项和实现时使用代码。 当我在代码中看到自动装配的依赖项时,我只需按 IDE 中的“转到实现”键,就会出现已知实现的列表。 在大多数情况下,只有一种实现,我就直接进入课堂。 不可能比这简单得多,而且我总是确切知道正在使用什么实现(我声称相反的情况更接近 xml 连接的事实 - 有趣的是你的观点如何变化!)
现在你可以说这只是一个非常简单的层,但是我们添加到系统中的每一层抽象都会增加复杂性。 我真的不认为 xml 给我使用过的任何系统带来任何真正的价值。
我使用过的大多数系统只有一个生产运行时环境的配置。 可能还有其他配置供测试等等。
我想说,完全自动装配是 spring 的 ruby-on-rails:它包含这样的概念:大多数用例都遵循正常且常见的使用模式。 使用 XML 配置,您允许大量可能/可能不是预期的一致/不一致的配置使用。 我见过很多 xml 配置过度不一致 - 它是否与代码一起重构? 没想到。 这些变化是有原因的吗? 通常不会。
我们在配置中几乎不使用限定符,并找到了其他方法来解决这些情况。 这是我们遇到的一个明显的“缺点”:我们稍微改变了编码方式,使其与自动装配交互更加顺畅:客户存储库不再实现通用的
Repository
接口,但我们使扩展Repository
的接口CustomerRepository
。 有时在子类化方面也有一两个技巧。 但它通常只是为我们指明了更强的打字方向,我发现这几乎总是一个更好的解决方案。但是,是的,您正在与一种特定的 DI 风格联系在一起,而这种风格主要是 spring 所做的。 我们甚至不再为依赖项创建公共设置器(所以你可能会说我们在封装/信息隐藏部门+1)我们的系统中仍然有一些 xml,但 xml 基本上仅 包含异常。 完全自动装配与 xml 完美集成。
我们现在唯一需要的就是将
@Component
、@Autowired
和其余部分包含在 JSR 中(例如 JSR-250),因此我们不必与 spring 配合。 这就是过去发生的事情的方式(java.util.concurrent
的东西浮现在脑海中),所以如果这种情况再次发生,我不会完全感到惊讶。For a long time I believed that there was a value in having a "centralized, declarative, configuration" like the xml files we all used to use. Then I realized that most of the stuff in the files wasn't configuration - it was never changed anywhere after development, ever. Then I realized that "centralized" only has value in quite small systems - only in small systems will you ever be able to grok a configuration file as a whole. And what is really the value of understanding the wiring as a whole, when the same "wirings" are mostly duplicated by dependencies in the code? So the only thing I've kept is meta-data (annotations), which is still kind-of declarative. These never change at runtime and they're never "configuration" data that someone will change on the fly - so I think keeping it in the code is nice.
I use full auto-wiring as much as I can. I love it. I won't go back to old-style spring unless threatened at gun-point. My reasons for preferring fully
@Autowired
have changed over time.Right now I think the most important reason for using autowiring is that there's one less abstraction in your system to keep track of. The "bean name" is effectively gone. It turns out the bean name only exists because of xml. So a full layer of abstract indirections (where you would wire bean-name "foo" into bean "bar") is gone. Now I wire the "Foo" interface into my bean directly, and implementation is chosen by run-time profile. This allows me to work with code when tracing dependencies and implementations. When I see an autowired dependency in my code I can just press the "go to implementation" key in my IDE and up comes the list of known implementations. In most cases there's just one implementation and I'm straight into the class. Can't be much simpler than that, and I always know exactly what implementation is being used (I claim that the opposite is closer to the truth with xml wiring - funny how your perspective changes!)
Now you could say that it's just a very simple layer, but each layer of abstraction that we add to our systems increase complexity. I really don't think the xml ever added any real value to any system I've worked with.
Most systems I've ever work with only have one configuration of the production runtime environment. There may be other configurations for test and so on.
I'd say that full autowiring is the ruby-on-rails of spring: It embraces the notion that there's a normal and common usage pattern that most use cases follow. With XML configuration you permit a lot of consistent/inconsistent configuration usage that may/may not be intended. I've seen so much xml configuration go overboard with inconsistencies - does it get refactored together with the code ? Thought not. Are those variations there for a reason? Usually not.
We hardly use qualifiers in our configuration, and found other ways to solve these situations. This is a clear "disadvantage" we encounter: We've slightly changed the way we code to make it interact smoother with autowiring: A customer repository no longer implements the generic
Repository<Customer>
interface but we make an interfaceCustomerRepository
that extendsRepository<Customer>
. Sometimes there's also a trick or two when it comes to subclassing. But it usually just points us in the direction of stronger typing, which I find is almost always a better solution.But yes, you're tying to a particular style of DI that mostly spring does. We don't even make public setters for dependencies any more (So you could argue that we're +1 in the encapsulation/information hiding department) We still have some xml in our system, but the xml basically only contains the anomalies. Full autowiring integrates nicely with xml.
The only thing we need now is for the
@Component
,@Autowired
and the rest to be included in a JSR (like JSR-250), so we don't have to tie in with spring. This is the way things have been happening in the past (thejava.util.concurrent
stuff springs to mind), so I wouldn't be entirely surprised if this happened again.