有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Jersey的java依赖注入

如果我使用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 */
    }
}

共 (4) 个答案

  1. # 1 楼答案

    除非您愿意,否则您不必使用外部库。有充分的证据表明,让CDI与Jersey一起正确工作目前是一件痛苦的事情。然而,我可以从经验中说,这是可以做到的,因为我自己已经做到了。我跳过这些障碍已经有一段时间了,但我似乎记得我们必须使我们的资源成为无状态EJB,才能让它工作。我本可以采取其他措施,但我现在不记得了

    当Jersey 2.0面世时,这应该会变得容易得多,因为他们将转而使用核心CDI实现,而不是自己的实现。有关更多信息,请参阅此错误:

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

  2. # 2 楼答案

    有一个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());
       } 
    }
    
  3. # 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注入的地方注入提供的实例

  4. # 4 楼答案

    我最终使用了GoogleGuice,这是一个轻量级DI框架,与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://stackoverflow.com/a/3296467--我最初有

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

    而不是排队

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

    但这导致Jersey尝试执行依赖项注入而不是Guice,这会导致运行时错误