Javadependency injection:XML或注释

注释变得stream行。 Spring-3支持它们。 CDI很大程度上依赖于他们(我不能使用CDI和注释,对不对?)

我的问题是为什么

我听到几个问题:

  1. “它有助于摆脱XML”。 但是,什么是坏的XML? 依赖性本质上是声明性的,而XML对于声明是非常好的(对于命令式编程来说非常糟糕)。 有了好的IDE(比如想法),编辑和validationXML非常容易,不是吗?

  2. “在许多情况下,每个接口只有一个实现”。 那不是真的! 几乎我的系统中的所有接口都有模拟testing的实现。

任何其他问题?

而现在我的XML的增加:

  1. 你可以在任何地方注入任何东西(不仅是有注释的代码)

  2. 我应该怎么做,如果我有一个接口的几个实现? 使用限定符? 但是这迫使我的class级知道需要什么样的注射。 这不利于devise。

基于XML的DI使我的代码变得清晰:每个类都不知道注入,所以我可以对它进行configuration并以任何方式进行unit testing。

你怎么看?

我只能从Guice的经验说话,但这里是我的看法。 简而言之,基于注解的configuration大大减less了将应用程序连接在一起所需的数量,并使得更容易更改什么取决于什么……往往不需要自己触摸configuration文件。 这是通过使最常见的情况变得非常微不足道,而使得某些相对罕见的情况稍微难以处理。

我认为如果课堂上“不知道注射”是过于教条化的问题。 代码中不应该提到注射容器。 我绝对同意这一点。 但是,我们必须清楚一点:注释不是代码 。 他们本身并没有改变一个类的行为方式……你仍然可以创build一个具有注释的类的实例,就好像它们根本不存在一样。 因此,您可以完全停止使用DI容器,并将注释留在那里,不会有任何问题。

当你select不提供有关类内注入的元数据提示(即注释)时,你正在扔掉关于类需要什么依赖关系的宝贵信息源。 你不得不在其他地方重复这些信息(比如说XML),或者依赖自动assembly等不可靠的魔法,这可能会导致意想不到的问题。

为了解决您的一些具体问题:

它有助于摆脱XML

XMLconfiguration有很多不好的地方。

  • 这非常详细。
  • 没有特殊的工具,它不是types安全的。
  • 它强制使用string标识符。 再次,不安全没有特殊的工具支持。
  • 不利用语言的特点,需要各种丑陋的构造来做一些简单的代码方法。

也就是说,我知道很多人一直在使用XML,所以他们相信这样做很好,我也不希望改变他们的想法。

在许多情况下,每个接口只有一个实现

对于应用程序的单个configuration (例如生产),每个接口通常只有一个实现。 关键是在启动应用程序时,通常只需要将接口绑定到单个实现。 它可能会被用于许多其他组件。 使用XMLconfiguration,您必须告诉每个使用该接口的组件使用该接口的一个特定绑定(或者,如果您喜欢,可以使用“bean”)。 使用基于注解的configuration,您只需声明一次绑定,其他所有事情都会自动处理。 这是非常重要的,并且大大减less了您必须编写的configuration数量。 这也意味着,当你添加一个新的依赖到一个组件时,你通常不需要改变任何有关你的configuration!

你有一些接口的模拟实现是无关紧要的。 在unit testing中,您通常只是创build模拟并将其传递给自己…这与configuration无关。 如果你设置一个完整的系统进行集成testing,使用某些接口,而不是改变任何东西。 对于系统的集成testing运行,您仍然只使用1个实现,您只需configuration一次即可。

XML:可以在任何地方注入任何东西

你可以在Guice中轻松做到这一点,我想你也可以在CDI中做到这一点。 所以这不像是通过使用基于注释的configuration系统完全阻止这样做。 也就是说,我敢说,大多数应用程序中的大多数注入类都是类,如果它们不在那里,您可以添加一个@Inject给自己。 标准的轻量级标准Java库(JSR-330)的存在使得更多的库和框架将来也可以更容易地为组件提供带@Inject注释的构造函数。

多个接口的实现

限定符是这个的一个解决scheme,在大多数情况下应该是很好的。 但是,在某些情况下,您确实想要在某个特定注入类中的参数上使用限定符,这样做通常不会奏效,因为您希望拥有该类的多个实例,每个实例都使用不同的接口实现或实例。 Guice用一种叫做PrivateModule的东西来解决这个问题。 我不知道CDI在这方面提供了什么。 但是再一次,这是一个less数派的情况,只要你能处理它,就不值得让其余的configuration受到影响。

我有以下原则:configuration相关的bean是用XML定义的。 其他一切 – 带注释。

为什么? 因为你不想改变类的configuration。 另一方面,在想要启用的类中编写@Service@Inject简单多了。

这不会以任何方式干扰testing – 注释只是由容器parsing的元数据。 如果你喜欢,你可以设置不同的依赖关系。

至于CDI – 它有一个扩展的XMLconfiguration,但你是正确的,它主要使用注释。 这是我不特别喜欢的东西。

在我看来,这更多的是品味的问题。

1)在我们的项目(使用Spring 3)中,我们希望XMLconfiguration文件只是:configuration。 如果不需要configuration(从最终用户的angular度来看)或其他问题不会强制在xml中完成,请不要将bean定义/配线放入XMLconfiguration中,请使用@Autowired等等。

2)使用Spring,如果存在多个,则可以使用@Qualifier来匹配接口的某个实现。 是的,这意味着你必须命名实际的实现,但我不介意。

在我们的例子中,使用XML处理所有的DI会使XMLconfiguration文件膨胀很多,尽pipe它可以在一个单独的xml文件(或文件)中完成,所以这不是有效的点)。 正如我所说,这是一个味道的问题,我只是认为通过注释来处理注入更简单,更简洁(只要查看类而不是通过XML文件就可以看到什么服务/存储库/寻找bean声明)。

编辑:这里有一个意见@Autowired与XML,我完全同意: Spring @Autowired使用

正如你指出的那样,我喜欢保持我的代码清晰。 在国际奥委会的原则下,XML至less对我来说更好。

dependency injectionconfiguration的基本原则是应用程序对象不应该负责查找他们所依赖的资源或协作者。 相反,IoC容器应该configuration对象,将应用程序代码中的资源查找外部化到容器中。 (没有EJB的J2EE开发 – Rod Johnson – 页码131)

再次,这只是我的观点,没有原教旨主义:)

编辑:有一些有用的讨论:

“但是,什么是坏的xml?” 这是另一个文件来pipe理,而另一个地方必须去寻找一个错误。 如果您的注释紧挨着您的代码,则更容易pipe理和debugging。

像所有的事情一样,dependency injection应该适度使用。 而且,所有注射剂都应该与应用程序代码分开,并转移到与main相关的代码中。

一般而言,应用程序应该有一个边界,将抽象应用程序代码与具体的实现细节分开。 所有跨越边界的源代码依赖关系应指向应用程序。 我把这个边界的具体方面称为主分区,因为这是“主”(或者相当于)应该存在的地方。

主分区由工厂实现,策略实现等组成。在边界的这一边,dependency injection框架应该这样做。 然后,这些注入的依赖关系可以通过常规手段跨越边界传递给应用程序。 (如作为参数)。

注入依赖的数量应该相对较小。 一打或更less。 在这种情况下,XML或注释之间的决定是没有意义的。

另外不要忘记Spring JavaConfig 。

就我而言,编写应用程序的开发人员不同,configuration应用程序的开发人员(不同部门,不同技术/语言),最后一个组织甚至无法访问源代码(在许多企业设置中都是如此)。 这使Guice无法使用,因为我不得不公开源代码,而不是使用实现应用程序的开发人员configuration的xml。

总体而言,我认为认识到提供组件和组装应用程序是两个不同的练习,并在需要时提供这种关注的分离是非常重要的。

我只是有一些东西要添加到已经在这里。

  • 对我来说,DIconfiguration是代码。 我想这样对待它,但是XML的本质在没有额外的工具的情况下阻止了这一点。

  • Spring JavaConfig在这方面是向前迈进的一大步,但它仍然有复杂性。 组件扫描,接口实现的自动魔术select,以及围绕@Configuration注解的类的CGLIB截取的语义,使得它比需要更复杂。 但是这仍然是XML的一步。

  • 从应用程序对象中分离IoC元数据的好处被夸大了,特别是在Spring中。 也许如果你仅限于Spring IoC容器,这将是事实。 但是Spring提供了构build在IoC容器(安全性,Web MVC等)上的广泛的应用程序堆栈。 只要你利用任何一种方法,无论如何你都被绑在容器上。

XML具有与应用程序代码本身明确分离的声明式样式的唯一好处。 这与DI关系保持独立。 缺点是冗长,重构稳健性差和一般的运行时失败行为。 与仅支持Java的IDE相比,只有一般的(XML)工具支持几乎没有什么好处。 除此之外,XML还带有性能开销,因此通常比代码解决scheme慢。

在重新分解应用程序代码时, Annoations经常被认为更加直观和强大。 他们也从像guice提供的更好的IDE指导中受益。 但是他们将应用程序代码与DI关注点混合在一 应用程序依赖于框架。 清晰分离几乎是不可能的。 当在同一地点(build设者,领域)根据其他情况(例如机器人腿问题)描述不同的注入行为时,注释也是有限的。 此外,他们不允许像你自己的来源一样对待外部类(库代码)。 因此他们被认为比XML运行得更快。

这两种技术都有严重的缺点。 所以我build议使用Silk DI 。 它在代码中定义了声明(很棒的IDE支持),但是与应用程序代码100%分开(没有框架依赖)。 它允许对待所有相同的代码,无论它是来自你的源还是外部库。 像机器人腿问题的问题很容易解决与通常的绑定。 此外,它有很好的支持,以适应您的需求。