2012-05-23 24 views
6

Si uso Jersey 1.12, y tengo múltiples clases de recursos, y todos ellos necesitan acceder a un contexto compartido, ¿cuál es la mejor forma de insertar una dependencia, ya sea en el constructor para la clase de recursos? , o en el método del controlador? ¿Necesito usar una biblioteca DI externa, o tiene Jersey algo incorporado?Inyección de dependencia con Jersey

es decir, tal vez el recurso para Foos es así:

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

y Bares:

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

Respuesta

12

Terminé usando Google Guice, que es un marco DI liviano que se integra bien con Jersey. Esto es lo que tenía que hacer:

En primer lugar, he añadido dependencias en el 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> 

que quería un DAO implementa como un conjunto unitario con una interfaz:

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

y una implementación concreta:

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

Decorado las clases de recursos como lo siguiente:

@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 ... 
    } 
} 

creado una clase que va a hacer las fijaciones:

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); 
      } 
     }); 
    } 
} 

que utilizan embarcadero en lugar de Glassfish para actuar realmente como servidor.En mi prueba de funcionamiento, que se ve algo como:

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(); 
} 

El EmptyServlet proviene de código de ejemplo de Sunny Gleason dada a cabo como respuesta a: https://stackoverflow.com/a/3296467 - que originalmente tenían

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

en lugar de la línea

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

Pero eso hizo que Jersey intentara realizar la inyección de dependencia en lugar de Guice, lo que provocó errores de tiempo de ejecución.

1

Hay un proyecto Jersey-muelle que soporta la inyección de dependencias primavera. Reemplace su jersey ServletContainer con SpringServlet, agregue un ContextLoaderListener a su web.xml y puede inyectar beans en sus componentes. Aquí hay un tutorial bastante decente de la configuración

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

EDITAR

He aquí una idea que no requiere la adición de cualquier dependencia. Cree su propio ServletContextListener que agregue sus objetos al ServletContext. A continuación inyectar el ServletContext en sus Recursos

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()); 
    } 

} 

Luego, en su recurso

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

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

que cuentan con un total de 4 Primavera dependencias que tendría que agregar. Eso parece bastante severo. –

+0

Se agregó otra sugerencia para usted – jeff

3

puede utilizar SingletonTypeInjectableProvider: http://jersey.java.net/nonav/apidocs/1.12/jersey/com/sun/jersey/spi/inject/SingletonTypeInjectableProvider.html

muestra:

ResourceConfig resourceConfig = new DefaultResourceConfig(); 
resourceConfig.getSingletons().add(
     new SingletonTypeInjectableProvider<Context, SingletonType>(
       SingletonType.class, new SingletonType()) {});{code} 

o puede crear SingletonTypeInjectableProvider descendiente anotar con @Provider agrégalo como clase. Puedes inyectar la instancia provista donde sea que necesites y donde la inyección estándar de Jersey entra en acción.

+0

Aquí hay una respuesta de cómo hacerlo con la anotación '@ Provider': http://stackoverflow.com/a/10899513/473775. – joscarsson

1

No tiene que usar una biblioteca externa a menos que lo desee. Está bien documentado que conseguir que CDI funcione correctamente con Jersey es actualmente un problema. Sin embargo, puedo decir por experiencia que se puede hacer por mí mismo. Ha pasado un tiempo desde que salté a través de esos aros, pero me parece recordar que teníamos que hacer que nuestros recursos EJB sin estado lo hicieran funcionar. Podrían haber otros pasos que tomé, pero ahora no los recuerdo.

Cuando sale Jersey 2.0 esto debería ser mucho más fácil ya que cambiarán a la implementación de Core CDI en lugar de la suya. Ver este error para obtener más información:

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

Cuestiones relacionadas