Jersey中的依赖注入

6
如果我正在使用Jersey 1.12,并且我有多个资源类,它们都需要访问一些共享上下文,那么最好的方法是在资源类的构造函数中注入依赖项,还是在处理程序方法中注入依赖项?我需要使用外部DI库,还是Jersey内置了一些东西?
例如,也许Foos的资源如下所示:
package com.example.resource;

import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.ws.rs.Path;

@Path("/some/api/path/foo")
public class FooResource
{
    @GET
    @Produces("text/html")
    public String getFoo(@QueryParam("id") String id)
    {
        Foo foo = /* get a Foo from some shared context based on id */
        /* Process foo into a String */
    }
}

对于酒吧:

package com.example.resource;

import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.ws.rs.Path;

@Path("/some/api/path/bar")
public class BarResource
{
    @GET
    @Produces("text/html")
    public String getBar(@QueryParam("id") String id)
    {
        Bar bar = /* get a Bar from some shared context based on id */
        /* Process bar into a String */
    }
}

http://jersey.java.net/documentation/latest/migration.html#mig-server-inject-custom-objects - tuxSlayer
https://dev59.com/S1UM5IYBdhLWcg3wKNyB - Rinke
4个回答

12

最终我使用了Google Guice,它是一个轻量级的依赖注入框架,能够很好地与Jersey集成。这是我所做的:

首先,在pom.xml文件中添加依赖项:

    <dependency>
        <groupId>com.google.inject</groupId>
        <artifactId>guice</artifactId>
        <version>3.0</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>com.sun.jersey.contribs</groupId>
        <artifactId>jersey-guice</artifactId>
        <version>1.12</version>
        <scope>compile</scope>
    </dependency>

我希望实现一个DAO,作为单例并具备接口:

public interface MySingletonDao
{
    // ... methods go here ...
}

还有一个具体的实现:

@Singleton
public class ConcreteMySingletonDao implements MySingletonDao
{
    // ... methods go here ...
}

像这样装饰资源类:

@Path("/some/path")
@RequestScoped
public class MyResource
{
    private final MySingletonDao mySingletonDao;

    @Inject
    public MyResource(MySingletonDao mySingletonDao)
    {
        this.mySingletonDao = mySingletonDao;
    }

    @POST
    @Produces("application/json")
    public String post() throws Exception
    {
            // ... implementation goes here ...
    }
}

创建了一个将执行绑定的类:

public class GuiceConfig extends GuiceServletContextListener
{
    @Override
    protected Injector getInjector()
    {
        return Guice.createInjector(new JerseyServletModule()
        {
            @Override
            protected void configureServlets()
            {
                bind(MyResource.class);
                bind(AnotherResource.class);
                bind(MySingletonDao.class).to(ConcreteMySingletonDao.class);
                serve("/*").with(GuiceContainer.class);
            }
        });
    }
}

我使用Jetty作为服务器,而不是Glassfish。在我的功能测试中,代码大致如下:

private void startServer() throws Exception
{
    this.server = new Server(8080);
    ServletContextHandler root =
        new ServletContextHandler(server, "/", ServletContextHandler.SESSIONS);

    root.addEventListener(new GuiceConfig());
    root.addFilter(GuiceFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
    root.addServlet(EmptyServlet.class, "/*");

    this.server.start();
}

EmptyServlet 来自 Sunny Gleason 在答案中提供的示例代码,该答案位于以下链接:https://dev59.com/DHE85IYBdhLWcg3wqVb5#3296467 -- 我最初有

root.addServlet(new ServletHolder(new ServletContainer(new PackagesResourceConfig("com.example.resource"))), "/*");

使用这行代码作为替代

root.addServlet(EmptyServlet.class, "/*");

但这导致Jersey尝试执行依赖注入而不是Guice,从而引起了运行时错误。


这更多的是控制反转而不是依赖注入。这听起来有点挑剔,但这个区别为我打开了一扇大门。 - maborg

3
你可以使用SingletonTypeInjectableProvider:http://jersey.java.net/nonav/apidocs/1.12/jersey/com/sun/jersey/spi/inject/SingletonTypeInjectableProvider.html 示例:
ResourceConfig resourceConfig = new DefaultResourceConfig();
resourceConfig.getSingletons().add(
        new SingletonTypeInjectableProvider<Context, SingletonType>(
               SingletonType.class, new SingletonType()) {});{code}

您可以创建SingletonTypeInjectableProvider的子类,并用@Provider注释将其添加为类。然后,您可以在需要和标准Jersey注入发生的任何地方注入提供的实例。

иҝҷйҮҢжңүдёҖдёӘдҪҝз”Ё@ProviderжіЁи§Јзҡ„ж–№жі•пјҡhttps://dev59.com/questions/fGgv5IYBdhLWcg3wCcWZ#10899513гҖӮ - joscarsson

1

有一个名为jersey-spring的项目,支持Spring依赖注入。将您的jersey ServletContainer替换为SpringServlet,将ContextLoaderListener添加到您的web.xml中,即可将bean注入到您的组件中。这里有一个相当不错的设置演示。

http://www.mkyong.com/webservices/jax-rs/jersey-spring-integration-example/

编辑

这里有一个不需要添加任何依赖项的想法。创建自己的ServletContextListener,将您的对象添加到ServletContext中。然后将ServletContext注入到您的资源中。

public class MyContextListener implements ServletContextListener
{

    @Override
    public void contextDestroyed(ServletContextEvent event)
    {
    }

    @Override
    public void contextInitialized(ServletContextEvent event)
    {
        ServletContext context = event.getServletContext();
        context.setAttribute(Foo.class.getName(), new FooImpl());
    }

}

然后在你的资源中

@Path("blah")
public class MyResource 
{
   private Foo foo;

   public MyResource(@Context ServletContext context)
   {
      foo = (Foo) context.getAttribute(Foo.class.getName());
   } 
}

1
我需要添加4个Spring依赖项,这似乎有些笨重。 - Shaggy Frog
为您添加了另一个建议。 - jeff

1

除非你想要,否则你不必使用外部库。已经有很好的文档表明,让CDI与Jersey正确地工作目前是一件麻烦的事情。然而,我可以从自己的经验中说,它是可以做到的。虽然跳过这些障碍已经有一段时间了,但我似乎记得我们必须使我们的资源无状态EJB才能使其正常工作。可能还有其他步骤,但我现在不记得了。

当Jersey 2.0发布时,这将变得更加容易,因为他们将转向使用核心CDI实现而不是他们自己的实现。请参见此错误以获取更多信息:

http://java.net/jira/browse/JERSEY-517


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