2012-05-23 4 views
6

Если я использую Джерси 1.12, и у меня есть несколько классов ресурсов, и все они должны получить доступ к некоторому общему контексту, что лучший способ вставить зависимость, будь то в конструкторе класса ресурсов , или в метод обработчика? Нужно ли мне использовать внешнюю библиотеку DI, или у Джерси есть что-то встроенное?Инъекция зависимостей с Джерси

т.е., возможно, ресурс для Фооса выглядит следующим образом:

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 */ 
    } 
} 
+0

http://jersey.java.net/documentation/latest/migration.html#mig-server-inject-custom-objects – tuxSlayer

ответ

12

Я закончил с помощью Google Guice, который представляет собой легкую конструкцию DI, которая хорошо сочетается с Джерси. Вот что я должен был сделать:

Во-первых, я добавил зависимостей в 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 происходит от образца кода Солнечного Глисона выданному в ответ на: https://stackoverflow.com/a/3296467 - я первоначально имел

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

вместо линии

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

Но это привело к тому, что Джерси попытался выполнить инъекцию зависимостей вместо Guice, что вызвало ошибки во время выполнения.

1

Существует джерси-весенний проект, который поддерживает введение Spring зависимостей. Замените ваш сержант ServletContainer на SpringServlet, добавьте ContextLoaderListener в ваш web.xml, и вы можете вставлять компоненты в свои компоненты. Вот довольно приличный пошаговое руководство по установке

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

EDIT

Вот идея, которая не требует добавления каких-либо зависимостей. Создайте свой собственный 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 которые я должен добавить. Это кажется довольно тяжелым. –

+0

Добавлено еще одно предложение для вас – jeff

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 добавьте его как класс. Вы можете вводить предоставленный экземпляр туда, где вам нужно, и где стандартная инъекция Джерси вступает в игру.

+0

Вот ответ, как это сделать с помощью аннотации '@ Provider': http://stackoverflow.com/a/10899513/473775. – joscarsson

1

Вам не нужно использовать внешнюю библиотеку, если вы этого не хотите. Хорошо документировано, что получение CDI для правильной работы с Джерси в настоящее время является болью. Однако из опыта я могу говорить, что это можно сделать, сделав это сам. Прошло некоторое время с тех пор, как я перепрыгнул через эти обручи, но, похоже, мы вспомнили, что нам нужно было заставить наши ресурсы Stateless EJB заставить его работать. Могли быть другие шаги, которые я предпринял, но я не помню их сейчас.

Когда выйдет Джерси 2.0, это должно стать намного проще, поскольку они перейдут на использование Core CDI, вместо их собственных. Смотрите эту ошибку для получения дополнительной информации:

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

Смежные вопросы