使用Jersey和Guice开发RESTful服务的实际建议

64
  • 从我在网上的了解来看,自2008年以来,Guice和Jersey整合的最新技术已经停滞不前,当时两个团队陷入了僵局。问题的关键是JAX-RS注释执行字段和方法注入,这与Guice自身的依赖注入不兼容。

  • 我发现的一些例子并没有详细说明:

  • Iqbalyusuf在Google App Engine Java上结合Jersey和Guice的帖子存在很多样板代码(手动获取和调用注射器)。我希望绑定和注入可以通过Guice注释在幕后进行。

  • Jonathan Curran的文章使用Jersey、Guice和JSR-250创建RESTful服务给了我希望,因为它更加实用(2010年),但它只展示了如何在Guice ServletModule中启动Jersey服务。然而,并没有展示任何真正的依赖注入示例。我想这是留给读者自己练习的。Curran的帖子可能是将Guice和Jersey连接起来的正确第一步,所以我打算从这里开始。

  • James Strachan在一篇文章中写道

    JAX-RS与Spring、Guice、GuiceyFruit或JBossMC等依赖注入框架配合良好 - 你可以选择任何一个你喜欢的。

    但从实践者的角度来看,我没有看到证据。

  • 我发现缺乏结合JAX-RS和Guice注释的实际示例和解释。例如:

    • 我认为我不能在Jersey中使用构造函数注入任何资源,因为Jersey想要控制这个过程。
    • 我不确定是否可以将@Inject与@PathParam、@QueryParam等结合使用。
    • 如何在MessageBodyWriter实现中使用注入。

    有没有人有非平凡的应用程序示例(最好带有源代码),将Jersey和Guice结合起来而不会牺牲其中任何一个?我将继续走这条路,但是Jersey和Guice列表上的碎片让我觉得我正在重复之前其他人的工作。


    1
    我无法想到将"@Inject"与"@PathParam、@QueryParam"注释结合使用的任何用例。你能提供一个吗? - Jonas
    11个回答

    52
    Guice与Jersey的集成并未停滞。相反,感谢Paul和他在Jersey后面的同事们,最新的1.7版本包含一个特殊的JerseyServletModule类,用于处理基于Guice的servlet。 在JAX-RS资源中使用基于Guice的构造函数注入是可行的。问题在于,在JAX-RS资源的构造函数中使用@QueryParam等JAX-RS注解。您不需要它!您可以使用Guice实现POJO注入,包括单例模式。然后,JAX-RS只是解析基于HTTP的RESTful API(如URL路径、查询参数、内容类型等)的“锦上添花”。您也不需要一个“工业强度”的例子。Guice和Jersey都经过了测试。您只需要一个完整的工作示例来查看它的工作原理。然后,您可以自己尝试高级功能。请查看以下链接,其中包含一个完整的示例,使用的是Guice 3.0和Jersey 1.7,这些都是最新版本: http://randomizedsort.blogspot.com/2011/05/using-guice-ified-jersey-in-embedded.html

    1
    在谷歌上搜索jersey+guice会出现很多过时的帖子,所以很难看出现在的状态真的很好。这是一个非常好的消息! - Waldheinz
    将接受的答案更改为此答案。@sunny-gleason的回答仍然不错,但是这个答案展示了Guice管理的构造函数注入的最远距离。感谢@Nehc。 - user23987
    请查看http://jersey.java.net/nonav/apidocs/1.11/contribs/jersey-guice/com/sun/jersey/guice/spi/container/servlet/package-summary.html,了解web.xml中的内容概述。 - Gili
    对于任何寻找 Dropwizard (0.6.1+) 解决方案的人,请参见 https://github.com/HubSpot/dropwizard-guice。它有一个有用的示例项目,可以帮助您开始使用请求范围的 Guice。请注意,DW 0.6.1 不会在 GuiceBundle 上调用 initialize(),因此您需要自己完成这个步骤(该示例不适用于 0.6.2+)。 - Gary
    3
    对于任何刚刚接触这个问题的人,需要注意的是,在使用Jersey 2.x时,无法将Guice注入到JAX-RS资源中。如果您希望看到这一问题得到解决(已经成为最受欢迎的Jersey问题),请点赞此问题链接:https://java.net/jira/browse/JERSEY-1950。 - Alden
    我不认为这个答案在讨论(最新的)Jersey2 + Guice 3时是正确的。你需要使用GuiceIntoHK2Bridge。如果没有显式绑定,你不能将Guice管理的对象注入到Jersey资源中! - Ben George

    20

    我在这里创建了一个 Guice/Jersey/Jetty/Jackson 的示例应用程序:

    http://github.com/sunnygleason/j4-minimal

    如果您有任何问题或建议,欢迎通过 Github 给我发送消息。目标是将其打造成 Java 堆栈上REST的入门级教程。

    希望这可以帮助您 - 祝您有愉快的一天!

    -Sunny


    2
    那个例子很好,让我完成了99%的工作,但是据我所知它实际上并没有使用Jackson。如果您尝试使用Jackson注释来隐藏字段(@JsonIgnore)之类的东西,您会发现这一点。为了闭合循环,您需要将 'serve("").with(GuiceContainer.class);' 更改为类似 'serve("").with(GuiceContainer.class, ImmutableMap.of(JSONConfiguration.FEATURE_POJO_MAPPING, "true")' 的内容。您还可以删除JacksonJsonProvider绑定,因为它们似乎没有在任何地方被@Inject引用。 - Bill
    感谢您发布示例代码。是否有可能消除EmptyServlet类的需要?也许可以使用Jersey或Guice中的一些新功能(或jersey-guice)来实现? :) - Shaggy Frog
    当我在Jersey Grizzly 2 TestContainer中运行示例时,我发现我不需要EmptyServletServletContextListenerFilter就足够了。 - hertzsprung

    9

    Daniel,感谢您提供的这个示例,它确实帮助了我。我已经成功运行了它,但是当我想要返回一个包含List<POJO>字段的稍微复杂一点的对象时,JSON中就没有这个List。您能否为此提供一些指导? - Nemanja Kovacevic

    3

    我认为我不能在任何资源上使用构造函数注入,因为Jersey想要控制这个过程。

    您无法使用Guice的构造函数注入,因为资源的创建由Jersey管理。在这种情况下,您可以在要注入的构造函数参数之前使用Jersey的@Inject注释:

    public NewsResource(@Inject NewsService service)
    

    3

    我最初尝试在我的Jersey注释类上使用Guice进行构造函数注入时遇到了类似的问题,但最终成功了,虽然只是一个相当琐碎的应用程序。

    我按照这里的说明操作:jersey-guice javadoc

    对我来说诀窍是需要从我的web.xml中删除标准的Jersey配置(如Jersey ServletContainer),并且仅保留Guice监听器和Guice过滤器。一旦我这样做了,Guice就会被调用来创建我的JAX-RS注释对象,并且Jersey会按预期注入我的JAX-RS注释方法(如@GET等)。


    上面的链接已经失效了。有没有最新的参考资料? - tatmanblue

    3
    尽管Sunny Gleason的示例非常好,但现在有些过时了。
    因此,今天我经历了很多挣扎,试图使Guice和Jersey彼此兼容,我创建了以下示例项目,以帮助您入门:

    https://github.com/MaliciousMustard/gradle-guice-jersey-jetty

    这个项目使用以下技术:
    1. Guice 用于 DI
    2. Jersey 用于 RESTful API
    3. Jackson 用于 POJO 到 JSON 的映射
    4. Jetty 用于 Web 服务器
    5. Gradle
    我想最重要的是,你不需要显式地指定每个新资源类。只要将它们添加到正在扫描的包中(查看 malicious.mustard.modules.JerseyModule),它们就会被自动发现!

    2

    GWizard 包含一个模块,可以让 Jersey2 和 Guice 直接集成。以下是一个完整的 JAX-RS 服务示例:

    public class Main {
        @Path("/hello")
        public static class HelloResource {
            @GET
            public String hello() {
                return "hello, world";
            }
        }
    
        public static class MyModule extends AbstractModule {
            @Override
            protected void configure() {
                bind(HelloResource.class);
            }
        }
    
        public static void main(String[] args) throws Exception {
            Guice.createInjector(new MyModule(), new JerseyModule()).getInstance(Run.class).start();
        }
    }
    

    请注意,这是基于Squarespace jersey2-guice adapter开发的,该适配器可能无法与未来发布的Jersey版本兼容。GWizard还提供了一个RESTEasy JAX-RS模块,建议使用。
    这里有一篇关于此事的博客文章,可能会有所帮助:http://blorn.com/post/107397841765/guice-and-jersey-2-the-easy-way

    1

    这些例子对我来说都是很好的起点,但我想要一个完整的MVC堆栈,其中Jersey-Guice是核心。我一直在努力完善它。截至本周,这个MVC堆栈已经作为原型完全部署到Maven中央仓库中。这意味着您现在可以使用一个Maven命令创建一个新的Jersey-Guice堆栈:

    mvn archetype:generate \
        -DarchetypeGroupId=org.duelengine \
        -DarchetypeArtifactId=duel-mvc-archetype \
        -DarchetypeVersion=0.2.1
    

    这将自动生成您指定的包命名的项目,因此您无需手动编辑模板项目。

    有关更多详细信息,请参阅项目Readme.md:https://bitbucket.org/mckamey/duel-mvc

    我使用的双面视图(客户端模板和服务器端视图)的详细信息在此处:https://bitbucket.org/mckamey/duel,但您可以替换为您使用的任何内容。


    1

    请问您能否帮我检查一下我的问题:https://dev59.com/XY_ea4cB1Zd3GeqPM1VO,我需要帮助,非常感谢。 - Marco Dinatsoli

    0

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