2012-05-23 17 views
6

Se utilizzo Jersey 1.12 e ho più classi di risorse e tutti devono accedere a un contesto condiviso, qual è il modo migliore per iniettare una dipendenza, sia nel costruttore per la classe di risorse o nel metodo del gestore? Devo utilizzare una libreria DI esterna o Jersey ha qualcosa di integrato?Iniezione di dipendenza con jersey

cioè forse la risorsa per Foos si presenta così:

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

e per Bar:

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

risposta

12

Ho finito per utilizzare Google Guice, che è un framework DI leggero che si integra bene con Jersey. Ecco cosa dovevo fare:

In primo luogo, ho aggiunto dipendenze nel 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> 

Volevo un DAO implementato come Singleton con un'interfaccia:

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

ea implementazione concreta:

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

Decorato le classi di risorse in questo modo:

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

creato una classe che farà le associazioni:

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

ho usato Molo invece di Glassfish di agire in realtà come server.Nel mio test funzionale, che assomiglia a:

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

Il EmptyServlet viene da codice di esempio Sunny Gleason dato fuori come una risposta a: https://stackoverflow.com/a/3296467 - Inizialmente avevo

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

al posto della linea

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

Ma ciò ha causato che Jersey tentasse di eseguire l'iniezione delle dipendenze anziché Guice, causando errori di runtime.

1

C'è un progetto jersey-molla che supporta l'iniezione di dipendenza primavera. Sostituisci la tua maglia ServletContainer con SpringServlet, aggiungi un ContextLoaderListener al tuo web.xml e puoi iniettare i fagioli nei tuoi componenti. Ecco una guida abbastanza decente del setup

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

EDIT

Ecco un'idea che non richiede l'aggiunta di eventuali dipendenze. Crea il tuo ServletContextListener che aggiunge gli oggetti al ServletContext. Poi iniettare il ServletContext nelle vostre risorse

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

} 

Poi, nel tuo Resource

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

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

io conto un totale di 4 Molla dipendenze che dovrei aggiungere. Sembra piuttosto pesante. –

+0

Aggiunto un altro suggerimento per voi – jeff

3

è possibile utilizzare SingletonTypeInjectableProvider: http://jersey.java.net/nonav/apidocs/1.12/jersey/com/sun/jersey/spi/inject/SingletonTypeInjectableProvider.html

campione:

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

oppure è possibile creare SingletonTypeInjectableProvider discendente annotarlo con @Provider aggiungilo come una classe. È possibile iniettare l'istanza fornita ovunque sia necessario e in cui viene iniettata l'iniezione standard Jersey.

+0

Ecco una risposta su come farlo con l'annotazione '@ Provider': http://stackoverflow.com/a/10899513/473775. – joscarsson

1

Non è necessario utilizzare una libreria esterna a meno che non si desideri. È ben documentato che far funzionare correttamente il CDI con Jersey è un problema. Tuttavia posso dire per esperienza che si può fare avendo fatto da solo. È passato un po 'di tempo da quando ho saltato quei cerchi, ma mi sembra di ricordare che dovevamo fare in modo che il nostro bean stateless Resources potesse farlo funzionare. Potrebbero esserci stati altri passi che ho fatto ma non li ricordo ora.

Quando esce Jersey 2.0, questo dovrebbe essere molto più semplice in quanto passeranno a utilizzare l'implementazione Core CDI anziché la propria. Vedere questo bug per maggiori informazioni:

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