2012-05-23 307 views
6

如果我使用澤西島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 */ 
    } 
} 
+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); 
      } 
     }); 
    } 
} 

我用碼頭,而不是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依賴注入球衣彈簧項目。用SpringServlet替換你的球衣ServletContainer,添加一個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春天我必須添加的依賴關係。這似乎相當嚴厲。 –

+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與澤西島正確合作目前是一種痛苦。不過,我可以從經驗中發現,自己做這件事可以做到。我跳過這些環節已經有一段時間了,但我似乎記得我們必須讓我們的資源無狀態EJB才能實現它。我可以採取其他措施,但現在我不記得那些。

當澤西2.0出來時,這應該得到一個更容易,因爲他們將切換到使用核心CDI實現,而不是自己的。看到這個錯誤的更多信息:

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