6

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

4 に答える 4

12

最終的には、Jersey とうまく統合できる軽量の DI フレームワークである Google Guice を使用することになりました。これが私がしなければならなかったことです:

まず、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 の代わりに Jetty を使用しました。私の機能テストでは、次のようになります。

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

これは、 https ://stackoverflow.com/a/3296467 で回答として提供されたEmptyServletSunny Gleason のサンプル コードからのものです。

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

線の代わりに

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

しかし、これにより、Jersey が Guice の代わりに依存性注入を実行しようとするため、実行時エラーが発生しました。

于 2012-05-26T06:42:26.810 に答える
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 で注釈を付けてクラスとして追加することもできます。提供されたインスタンスは、必要に応じて、標準的なジャージー インジェクションが開始される場所にインジェクトでき​​ます。

于 2012-05-24T04:58:40.407 に答える
1

Spring依存性注入をサポートするjersey-springプロジェクトがあります。ジャージのServletContainerをSpringServletに置き換え、ContextLoaderListenerをweb.xmlに追加すると、Beanをコンポーネントに注入できます。これがセットアップのかなりまともなウォークスルーです

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

編集

これは、依存関係を追加する必要がないアイデアです。オブジェクトをServletContextに追加する独自のServletContextListenerを作成します。次に、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());
   } 
}
于 2012-05-24T00:08:17.020 に答える
1

必要でない限り、外部ライブラリを使用する必要はありません。CDI を Jersey で正しく動作させることは、現在のところ困難であることは十分に文書化されています。しかし、私は自分でやったことができると経験から話すことができます. これらのフープを飛び越えてからしばらく経ちましたが、それを機能させるためにリソース ステートレス EJB を作成する必要があったことを思い出しているようです。私が取った他のステップがあったかもしれませんが、今は思い出せません。

Jersey 2.0が登場すると、独自の代わりにCore CDI実装を使用するように切り替えられるため、これは非常に簡単になるはずです. 詳細については、このバグを参照してください。

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

于 2012-10-18T16:37:57.927 に答える