自动装配和手工装配
自动装配是一种特殊的装配,其中注入依赖项不是显式的,而是实际上由容器隐式管理的。 本文试图提供一些有关使用自动装配的缺点的相关信息。 尽管以Spring为例,但是相同的推理也可以应用于JavaEE的CDI 。
自动装配基础
自动装配香料
自动装配具有不同的风格:
- 按类型自动装配意味着Spring将寻找与setter中使用的类型匹配的可用bean。 例如,对于具有
setCar(Car car)
方法的bean,Spring将在bean上下文中查找Car
类型(或其子类型之一)。 - 通过名称自动装配意味着Spring搜索策略基于bean名称。 对于前面的示例,Spring将查找一个名为
car
的bean,而不管其类型如何。 这都需要命名Bean(这里没有匿名Bean),并暗示开发人员负责任何类型的mismatch(如果car
Bean是Plane
类型)。
自动装配也可以用于构造函数注入。
通过XML配置自动装配
让我们首先消除一些误解:自动装配并不意味着注释。 实际上,自动布线从很早以前就可以通过XML使用,并且可以使用以下语法启用。
<beanautowire="byType"class="some.Clazz"/>
这意味着Spring将尝试使用setter查找合适的类型来填充依赖项。
可选的自动装配参数包括:
- 按名称:Spring将使用bean名称而不是按类型匹配
- 构造函数:构造函数注入仅限于按类型
- 自动检测:使用构造函数注入,但是如果找不到足够的构造函数,则退回到按类型
通过注释配置自动装配
可用的注释如下:
注解 | 描述 | 资源 |
---|---|---|
@org.springframework.bean.factory.Autowired | Wires by type | Spring 2.5+ |
@javax.annotation.Resource | Wires by name | Java EE 5+ |
@javax.inject.Inject | Wires by type | Java EE 6+ |
@javax.inject.Qualifier | Narrows type wiring | Java EE 6+ |
依赖注入就是将您的类彼此分离以使其更具可测试性。 通过注解自动装配将注解的类与注解库紧密耦合。 诚然,对于Spring的@Autowired来说,这比其他应用程序服务器通常提供的其他条件更糟。
到底为什么这么糟糕?
自动装配就是简化依赖注入,尽管乍一看似乎很诱人,但是在现实项目中却无法维护。
显式依赖项注入-猜猜是什么,显式定义单个Bean以匹配所需的依赖项。 更好的是,如果使用Java配置,则在编译时对其进行验证。
相反,自动装配是在Spring上下文中表示对所有可用bean的约束,以便只有一个与所需的依赖项匹配。 实际上,您将接线委托给Spring,让他负责为您找到合适的bean。 这意味着,如果您之前的约束不适用于新的Bean,则通过在上下文中添加Bean会带来提供多个匹配项的风险 。 项目越大,团队越大(或团队数量甚至更糟),上下文越大,风险越高。
例如,假设您通过一个实现构建了一个真正不错的服务,那么您需要将其注入某个地方。 一段时间后,有人注意到您的服务,但由于某种原因创建了替代实现。 通过在上下文中声明这个新bean以及前者,它将破坏容器的初始化! 更糟糕的是,它可能在应用程序的完全不同的部分中完成,似乎与前者没有任何联系。 至此,好运来分析一下错误的原因。
请注意,按名称自动装配甚至更糟,因为Bean名称即使在不同类型的层次结构中也有可能发生冲突。
在Spring中,自动装配不好,但在CDI中更糟,因为CDI中类路径中的每个类都可以作为注入对象。 顺便说一句,任何阅读这篇文章的CDI专家都将解释为什么自动装配是DI的唯一方法? 那将是真正的启发。
摘要
在这篇文章中,我试图解释什么是自动装配。 可以使用它,但是现在您应该意识到它的缺点。 恕我直言,您只应将其用于原型设计或概念的快速验证,一次使用后可以丢弃的所有内容。 如果确实需要,则首选按类型接线而不是按名称接线,因为至少它的匹配不依赖于字符串。
自动装配和手工装配