web-dev-qa-db-ja.com

グリズリーを実行しているJava seでWebサービス(jaxrs / jersey)にCDIインジェクトを有効にする方法は?

安らかなWebサービスリソースへのリソースのCDIインジェクションを許可するにはどうすればよいですか?私は標準のJava溶接2(cdi)、ジャージ(jaxrs)、およびグリズリー(Webサーバー)を使用して実行しています)。これが私の単純なWebリソースです。

import training.student.StudentRepository;
import javax.inject.Inject;
import javax.ws.rs.*;

@Path("student")
public class StudentWebResource {
  @Inject
  private StudentRepository studentRepository;  

  @GET
  @Path("count")
  @Produces(MediaType.TEXT_PLAIN)
  public Integer getCount() {
    return studentRepository.studentCount();
  }
}

そして、これが私の単純なWebサーバーを起動する方法です。

public class Main {
  public static void main(String[] args) throws Exception {
    startCdiApplication();
  }

  public static void startCdiApplication() throws Exception {
    Weld weld = new Weld();
    try {
      WeldContainer container = weld.initialize();
      Application application = container.instance().select(WebServer.class).get();
      application.run();
    } 
    finally {
      weld.shutdown();
    }
  }
}

そして、CDI注入の解決に溶接を使用するようにジャージーに通知するには、コードを変更する必要があると思います。

...
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;

public class WebServer implements Application {

  /*
   * startup the grizzly http server to make available the restful web services
   */
  private void startWebServer() throws IOException, InterruptedException {
    final ResourceConfig resourceConfig = new ResourceConfig().packages("training.webservice").register(new JacksonFeature());
    final HttpServer server = GrizzlyHttpServerFactory.createHttpServer(getBaseUri(), resourceConfig);
    server.start();
    Thread.currentThread().join();
  }

  ...

  @Override
  public void run() throws IOException, InterruptedException {
    startWebServer();
  }
}
12
Brice Roncace

このstackoverflow post を見た後、次のソリューションを実装しました。それが最善のルートかどうかはわかりませんが、うまくいきました。

Hk2バインダーを作成し、バインダーを登録しました。

public class WebServiceBinder extends AbstractBinder {

  @Override
  protected void configure() {
    BeanManager bm = getBeanManager();
    bind(getBean(bm, StudentRepository.class))
        .to(StudentRepository.class);
  }

  private BeanManager getBeanManager() {
    // is there a better way to get the bean manager?
    return new Weld().getBeanManager();
  }

  private <T> T getBean(BeanManager bm, Class<T> clazz) {
    Bean<T> bean = (Bean<T>) bm.getBeans(clazz).iterator().next();
    CreationalContext<T> ctx = bm.createCreationalContext(bean);
    return (T) bm.getReference(bean, clazz, ctx); 
  }
}

次に、ResourceConfigのインスタンス化を上から次のように変更しました。

final ResourceConfig resourceConfig = new ResourceConfig()
    .packages("training.webservice")
    .register(new JacksonFeature())
    .register(new WebServiceBinder());
13
Brice Roncace

選択された回答はしばらく前のものです。カスタムHK2バインダーですべてのバインディングを宣言することは実用的ではありません。依存関係を1つ追加する必要がありました。 Glassfish用に設計されていますが、他のコンテナに完全に適合します。 Tomcat/Grizzlyを使用しています。

   <dependency>
        <groupId>org.glassfish.jersey.containers.glassfish</groupId>
        <artifactId>jersey-gf-cdi</artifactId>
        <version>2.14</version>
    </dependency>

これはJerseyTestの例です(mainメソッドから実行する場合も同じ原則です)。リソースをインスタンス化する前に、weld-seへの依存関係を宣言し、Weldコンテナーを宣言する必要がありました。これも同様ですが、そのままで機能します。

public class GrizzlyTest extends JerseyTest {
    private Weld weld;
    private WeldContainer container;

    @Override
    protected Application configure() {
        weld = new Weld();
        container = weld.initialize();
        return new ResourceConfig(MyResource.class);
    }

    @Test
    public void test() {
        System.out.println(target("myresource").request().get(String.class));
    }

    @After
    public void after() {
        weld.shutdown();
    }
}
5
otonglet

少なくともWeld2.2.0.Final以降、HK2バインダーを台無しにする必要はありません。

公式の溶接 ドキュメント は、登録する必要があると述べていますorg.jboss.weld.environment.servlet.Listener。ドキュメントから抜粋したコード:

public class Main {
    public static void main(String[] args) throws ServletException, LifecycleException {
        Tomcat tomcat = new Tomcat();
        Context ctx = Tomcat.addContext("/", new File("src/main/resources").getAbsolutePath());

        Tomcat.addServlet(ctx, "hello", HelloWorldServlet.class.getName());
        ctx.addServletMapping("/*", "hello");

        ctx.addApplicationListener(Listener.class.getName());

        Tomcat.start();
        Tomcat.getServer().await();
    }

    public static class HelloWorldServlet extends HttpServlet {
        @Inject
        private BeanManager manager;

        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setContentType("text/plain");
            resp.getWriter().append("Hello from " + manager);
        }
    }
}

上記のサーブレットリスナーは、Weldコンテナのライフサイクル全体を管理します。したがって、次のことを行う必要はありません。

 Weld weld = new Weld();
 WeldContainer container = weld.initialize();

[〜#〜] update [〜#〜]@ EdMeloが指摘したように、GrizzlyHTTPサーバーは完全に準拠したサーブレットコンテナではありません。私はこれを知りませんでした、このヒントに感謝します。ですから、私の答えがまだここに当てはまるかどうかはわかりません。

2
G. Demecki