Google Guice与PicoContainer的依赖注入比较

107

我的团队正在研究依赖注入框架,并试图在使用Google-Guice和PicoContainer之间做出决定。

我们希望从框架中获得以下几点:

  1. 小的代码占用空间 - 我所说的小的代码占用空间是指我们不想在代码库中到处都是依赖注入代码。如果我们需要以后进行重构,我们希望这尽可能容易。
  2. 性能 - 每个框架在创建和注入对象时的开销有多大?
  3. 易用性 - 是否存在大量学习曲线?我们是否必须编写大量代码才能使一些简单的东西工作?我们希望尽可能少地配置。
  4. 社区规模 - 更大的社区通常意味着项目将继续得到维护。我们不想使用一个框架,然后不得不修复自己的错误;)此外,我们沿途遇到的任何问题都可以(希望)由框架的开发者/用户社区回答。

非常感谢对这两个框架根据列出的标准进行比较。任何有助于比较这两个框架的个人经验也将非常有帮助。

免责声明:我在依赖注入方面相对新手,请原谅我如果我问了一个与此讨论无关的问题。


更新:您可能还想考虑使用CDI 2.0 - Java的上下文和依赖注入。自2017年4月起,已在JSR 365中标准化。 - Basil Bourque
在这里稍晚一些,还应该提到Dagger2,它可以在编译时完成魔法,而不是运行时,确保代码能够运行。 - Thorbjørn Ravn Andersen
6个回答

121

您可能希望将Spring加入您考虑的依赖注入框架列表中。以下是一些问题的答案:

与框架的耦合

Pico - Pico倾向于不鼓励使用setter注入,但除此之外,您的类不需要了解Pico。只有需要了解装配的部分需要知道(对于所有DI框架都是如此)。

Guice - Guice现在支持标准JSR 330注释,因此您不再需要在代码中使用Guice特定的注释。Spring也支持这些标准注释。Guice的开发人员认为,如果没有运行Guice注释处理器,这些注释不应该对您决定使用其他框架产生影响。

Spring - Spring旨在允许您避免在代码中提到Spring框架。因为他们有很多其他的帮助程序/实用工具等等,所以依赖Spring代码的诱惑相当强烈。

性能

Pico - 我不太熟悉Pico的速度特性。

Guice - Guice被设计成快速的,参考文献中提到了一些数字进行比较。如果速度是主要考虑因素之一,应该考虑使用Guice或手动装配。

Spring - Spring可能会比较慢。已经有工作来加快速度,使用JavaConfig库可以提高速度。

易用性

Pico - 简单易配置。Pico可以为您做一些自动装配的决策。不清楚它如何适用于非常大的项目。

Guice - 简单易配置,只需添加注释并从AbstractModule继承以将其绑定在一起。随着配置最小化,适用于大型项目的规模扩展良好。

Spring - 相对容易配置,但大多数示例使用Spring XML作为配置方法。Spring XML文件随着时间的推移可能变得非常庞大和复杂,并且需要加载时间。考虑使用Spring和手工制作的依赖注入的混合来克服这个问题。

社区规模

Pico - 小型

Guice - 中等规模

Spring - 大型

经验

Pico - 我没有太多关于Pico的经验,但它不是一个广泛使用的框架,因此很难找到资源。

Guice - Guice是一个流行的框架,当你在开发中频繁重启大型项目时,它的速度优势是受欢迎的。我担心配置的分布式性质,即很难看到我们整个应用程序是如何组合在一起的。在这方面有点像AOP。

Spring - Spring通常是我的默认选择。话虽如此,XML可能会变得繁琐,导致速度变慢让人感到烦恼。我经常使用手工制作的依赖注入和Spring的组合。当您真正需要基于XML的配置时,Spring XML非常好用。Spring还投入了大量精力使其他框架更具有依赖注入友好性,这可能很有用,因为它们在这样做时经常使用最佳实践(JMS、ORM、OXM、MVC等)。

参考文献


1
我从别人那里学到的是,PicoContainer比Guice更轻量级。此外,通过查看PicoContainer文档,它似乎也更容易使用。它会自己搜索构造函数中的依赖项,您不需要指定要使用哪个构造函数。它只是使用匹配的构造函数。 - Kissaki
2
没错,我现在非常喜欢PicoContainer。它是一个“保持简单却有效”的解决方案,使我不得不认为Spring已经过时且臃肿。Guice也很好(有谷歌这样的靠山),但我相信Pico拥有更多的特性和灵活性,因为它更老一些。看到优秀的替代方案取代了恶心的XML配置,真是太棒了! - Manius
仅代表个人观点:我从Pico转换到Guice,因为我觉得Guice更容易使用。向组件添加注释会增加依赖性,但对我们来说这不是一个重要因素,因为Guice基本上只有两个JAR包。另一方面,在构造函数上使用@Inject可以让其他开发人员知道该对象是一个组件。话虽如此,我并不认为Pico有任何问题。我只是发现Guice稍微更容易使用一些。 - Joshua Davis
1
我在许多非常大型(并且使用频繁)的项目中使用Pico(每个容器中定义了数百种组件类型),并使用了它的几乎所有功能,对它感到非常满意。 - jhouse
2
我刚用Guice/Spring/PicoContainer做了个简单的性能测试 - Guice和PicoContainer非常相似。在某些情况下,Guice稍微快一点。Spring在所有情况下都非常慢。 - Joshua Davis

27

jamie.mccrindle提供的答案实际上非常好,但我感到困惑的是,既然有更优秀的替代品(Pico和Guice),为什么Spring是默认选择。 我认为Spring的流行已经达到了巅峰,现在它只是凭借所产生的炒作(以及所有其他“跟风”的Spring子项目)存活下来。

Spring唯一的真正优势是社区规模(而且坦白地说,由于规模和复杂性,它是必需的),但是Pico和Guice不需要庞大的社区,因为他们的解决方案更清晰、更有组织、更优雅。 Pico似乎比Guice更灵活(你可以在Pico中使用注释,也可以不用-它非常高效)。 (编辑:想说的是非常灵活而不是非常高效。)

Pico的微小大小和缺少依赖项是一个重要的胜利,这不应该被低估。现在要使用Spring需要下载多少兆字节? 它是一个笨拙混乱的巨型jar文件,并带有所有依赖项。 直觉认为,这样一个高效而“小”的解决方案应该比类似Spring的东西具有更好的可扩展性和性能。 Spring的膨胀真的会让它更好地扩展吗?这是个怪异的世界吗? 在证明(并解释)之前,我不会假设Spring“更具可扩展性”。

有时候创建一个好的东西(Pico/Guice),然后不要去加任何臃肿和厨房水槽功能,通过推出无尽新版本来实现真的很奏效...


1
你介意说一下为什么Pico和Guice比Spring更加优越吗? - Thorbjørn Ravn Andersen
4
我原以为我做到了 - 基本上,它们同样擅长 DI,它们更简单/更小/更干净,没有或很少依赖。这并不是说 Spring 从不有意义(我相信有些情况下它确实有用),我只是想说如果你的要求被满足,那么更简单更好。对于大多数项目来说,仅需要一些小型支持库即可。 - Manius
有趣的是,这篇文章12年后仍然得到了赞,但我现在甚至不完全同意它。更不用说Pico已经被忽视到无需再去关注了;这很遗憾,因为它曾经是一个非常好的简单、专注的工具。更新到2022年,由于Spring Boot已经出现了,我认为它是在这篇回答之后大约4年左右首次推出的,情况已经大不相同了。除非我需要非常轻量级的东西,否则我通常会默认使用Spring。 - Manius

13

注:这更像是一条评论/牢骚,而不是一个答案

PicoContainer很棒。如果他们修复了他们的网站,我将会切换回来。现在它真的很混乱:

我现在正在使用Guice 2.x,即使它更大并且拥有的功能更少。找到文档很容易,而且它的用户组非常活跃。但是,如果Guice 3的方向任何迹象表明,它看起来像是开始变得臃肿,就像Spring在早期一样。

更新:我给Pico Container的人留了一个评论,他们对网站进行了一些改进。现在好多了!


但是Codehaus网站仍然冻结,没有任何关于迁移的信息。我以为Pico已经死了 ;) - Vladislav Rastrusny
1
如果网站代码没有及时更新,可能意味着该项目已经落后于关键质量水平。 - Thorbjørn Ravn Andersen
@ThorbjørnRavnAndersen 是的。不幸的是,我认为Pico已经被Guice和CDI所取代。 - Joshua Davis
5
截至2013年3月8日,picocontainer.org网站似乎被一个域名抢注者占据了。现在,picocontainer.com似乎是官方网站。 - dOxxx

3
如果你想要一个极简的依赖注入容器,可以看看Feather。仅支持原生的JSR-330 DI功能,但占用空间小(16K,无依赖项)且性能不错。适用于安卓系统。

嘿,Feather 真是太棒了!我用它实现了一个DI插件,并应用于ActFramework上。我进行了一些更新,例如根据需要自动调用injectFields,并支持注入监听器。如果您希望我发送回拉取请求,请告诉我。 - Gelin Luo
@Green,我看到你已经转向使用Genie了。你能分享一下使用Feather的经验吗? - beerBear
1
@beerBear Feather非常轻量级且在大多数DI用例中非常易于使用。然而,由于我正在开发一个全栈MVC框架,我需要一个实现完整JSR330规范的解决方案。这就是为什么我转向了Genie。 - Gelin Luo
@green 我很感谢你的帖子,让我更好地理解了。 - beerBear

3

这是一个老问题,但现在你可以考虑在你的Android应用项目中使用Dagger (https://github.com/square/dagger)。

Dagger在编译时进行代码生成,因此您可以获得更短的启动时间和更少的内存使用。


我喜欢Dagger,但似乎公共存储库中尚未有非Android项目的Gradle插件(即用于“常规”Java项目的Gradle插件)。如果公共存储库中有插件,我会考虑将其用于Java项目。 - Joshua Davis

0

虽然我喜欢 PicoContainer 的简单性和缺乏依赖性,但我建议使用 CDI,因为它是 Java EE 标准的一部分,所以您没有供应商锁定。

就其侵入性而言,其主要问题是需要容器,并且使用一个相对空的 META-INF/beans.xml 文件(必须指示 jar 正在使用 CDI)和注释的使用(尽管它们是标准的)

我用于自己的项目的轻量级 CDI 容器是 Apache Open Web Beans。 尽管需要一些时间来弄清楚如何创建一个简单的应用程序(不像 Pico),但它看起来像这样。

public static void main(final String[] args) {
    final ContainerLifecycle lifecycle = WebBeansContext.currentInstance()
            .getService(ContainerLifecycle.class);
    lifecycle.startApplication(null);

    final BeanManager beanManager = lifecycle.getBeanManager();
    // replace Tester with your start up class
    final Bean<?> bean = beanManager.getBeans(Tester.class).iterator()
            .next();

    final Tester b = (Tester) lifecycle.getBeanManager().getReference(bean,
            Tester.class, beanManager.createCreationalContext(bean));
    b.doInit();
}

2
如果您在库代码中坚持使用JSR-330,那么可以将容器特定的代码最小化。 - Thorbjørn Ravn Andersen
你在自动化测试中仍然需要特定于容器的代码。虽然这并不意味着你在实际代码中需要容器特定的代码(除非你打算运行自己的“main”函数,在我为自己编写的一个应用程序中我确实使用了这种方法)。 - Archimedes Trajano

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接