私はGuiceのユーザーではないので、この回答はJerseyのDIフレームワークHK2を使用しています。基本的な設定レベルでは、HK2はGuiceの設定とあまり変わりません。たとえばGuiceの場合、AbstractModule
があり、HK2はAbstractBinder
です。どちらのコンポーネントでも、同様の構文のbind(..).to(..).in(Scope)
を使用します。 1つの違いは、Guiceの場合はbind(Contract).to(Impl)
、HK2の場合はbind(Impl).to(Contract)
です。
HK2にはFactory
もあり、注入可能なオブジェクトのより複雑な作成を可能にします。あなたの工場では、構文bindFactory(YourFactory.class).to(YourContract.class)
を使用します。
これは、次のような方法でユースケースを実装できます。
上記2つのSessionFactory
sがシングルトンスコープでかつによってバインドされます注意してくださいフランスのSessionFactory
public class FrenchSessionFactoryFactory implements Factory<SessionFactory> {
@Override
public SessionFactory provide() {
...
}
@Override
public void dispose(SessionFactory t) {}
}
ためFactory
を作成し、英語SessionFactory
public class EnglishSessionFactoryFactory implements Factory<SessionFactory> {
@Override
public SessionFactory provide() {
...
}
@Override
public void dispose(SessionFactory t) {}
}
ためFactory
を作成します。名。
別のFactory
を作成してリクエストスコープに入れると、要求コンテキスト情報が使用されます。このファクトリは、上記の2つの名前を(名前バインディングを使用して)名前で入力し、要求コンテキスト情報から適切なSessionFactory
を返します。単にクエリパラメータ
public class SessionFactoryFactory
extends AbstractContainerRequestValueFactory<SessionFactory> {
@Inject
@Named("EnglishSessionFactory")
private SessionFactory englishSessionFactory;
@Inject
@Named("FrenchSessionFactory")
private SessionFactory frenchSessionFactory;
@Override
public SessionFactory provide() {
ContainerRequest request = getContainerRequest();
String lang = request.getUriInfo().getQueryParameters().getFirst("lang");
if (lang != null && "fr".equals(lang)) {
return frenchSessionFactory;
}
return englishSessionFactory;
}
}
を使用する例を下回る次に、あなただけのあなたのDAOに(私たちは別の名前を与えるであろう)SessionFactory
を注入することができます。一緒にすべてをバインドする
public class IDaoImpl implements IDao {
private final SessionFactory sessionFactory;
@Inject
public IDaoImpl(@Named("SessionFactory") SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
、あなたはここで次の実装
public class PersistenceBinder extends AbstractBinder {
@Override
protected void configure() {
bindFactory(EnglishSessionFactoryFactory.class).to(SessionFactory.class)
.named("EnglishSessionFactory").in(Singleton.class);
bindFactory(FrenchSessionFactoryFactory.class).to(SessionFactory.class)
.named("FrenchSessionFactory").in(Singleton.class);
bindFactory(SessionFactoryFactory.class)
.proxy(true)
.proxyForSameScope(false)
.to(SessionFactory.class)
.named("SessionFactory")
.in(RequestScoped.class);
bind(IDaoImpl.class).to(IDao.class).in(Singleton.class);
}
}
に似AbstractBinder
は、バインダー
- 二つの異なる言語の特定について注意すべきいくつかのものです使用します。
SessionFactory
は名前でバインドされています。ステップ3で確認できるように、@Named
注入に使用されます。
- 決定を行う要求スコープ付きファクトリにも名前が付けられています。
proxy(true).proxyForSameScope(false)
があります。これは、IDao
がシングルトンになると仮定し、 "選択された" SessionFactory
がリクエストスコープにあると仮定しているため、リクエストからリクエストに変更されるため、実際にSessionFactory
を挿入することはできません。プロキシを注入する。 IDao
がシングルトンではなくリクエストスコープだった場合、その2つの行を省略することができます。 daoリクエストをスコープにするほうが良いかもしれませんが、シングルトンとしてどのように行うべきかを示したかっただけです。
このトピックの詳細については、Injecting Request Scoped Objects into Singleton Scoped Object with HK2 and Jerseyも参照してください。
次に、あなただけのジャージーでAbstractBinder
を登録する必要があります。そのためには、のregister(...)
メソッドを使用してください。 See also、web.xml設定が必要な場合。
これはそれです。以下はJersey Test Frameworkを使った完全なテストです。他のJUnitテストと同様に実行できます。 SessionFactory
は実際の休止状態SessionFactory
ではなく、ダミークラスです。できるだけ短くしておくだけですが、通常のHibernate初期化コードに置き換えてください。
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.ContainerRequest;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.internal.inject.AbstractContainerRequestValueFactory;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
/**
* Stack Overflow https://stackoverflow.com/q/35189278/2587435
*
* Run this like any other JUnit test. There is only one required dependency
*
* <dependency>
* <groupId>org.glassfish.jersey.test-framework.providers</groupId>
* <artifactId>jersey-test-framework-provider-inmemory</artifactId>
* <version>${jersey2.version}</version>
* <scope>test</scope>
* </dependency>
*
* @author Paul Samsotha
*/
public class SessionFactoryContextTest extends JerseyTest {
public static interface SessionFactory {
Session openSession();
}
public static class Session {
private final String language;
public Session(String language) {
this.language = language;
}
public String get() {
return this.language;
}
}
public static class EnglishSessionFactoryFactory implements Factory<SessionFactory> {
@Override
public SessionFactory provide() {
return new SessionFactory() {
@Override
public Session openSession() {
return new Session("English");
}
};
}
@Override
public void dispose(SessionFactory t) {}
}
public static class FrenchSessionFactoryFactory implements Factory<SessionFactory> {
@Override
public SessionFactory provide() {
return new SessionFactory() {
@Override
public Session openSession() {
return new Session("French");
}
};
}
@Override
public void dispose(SessionFactory t) {}
}
public static class SessionFactoryFactory
extends AbstractContainerRequestValueFactory<SessionFactory> {
@Inject
@Named("EnglishSessionFactory")
private SessionFactory englishSessionFactory;
@Inject
@Named("FrenchSessionFactory")
private SessionFactory frenchSessionFactory;
@Override
public SessionFactory provide() {
ContainerRequest request = getContainerRequest();
String lang = request.getUriInfo().getQueryParameters().getFirst("lang");
if (lang != null && "fr".equals(lang)) {
return frenchSessionFactory;
}
return englishSessionFactory;
}
}
public static interface IDao {
public String get();
}
public static class IDaoImpl implements IDao {
private final SessionFactory sessionFactory;
@Inject
public IDaoImpl(@Named("SessionFactory") SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
public String get() {
return sessionFactory.openSession().get();
}
}
public static class PersistenceBinder extends AbstractBinder {
@Override
protected void configure() {
bindFactory(EnglishSessionFactoryFactory.class).to(SessionFactory.class)
.named("EnglishSessionFactory").in(Singleton.class);
bindFactory(FrenchSessionFactoryFactory.class).to(SessionFactory.class)
.named("FrenchSessionFactory").in(Singleton.class);
bindFactory(SessionFactoryFactory.class)
.proxy(true)
.proxyForSameScope(false)
.to(SessionFactory.class)
.named("SessionFactory")
.in(RequestScoped.class);
bind(IDaoImpl.class).to(IDao.class).in(Singleton.class);
}
}
@Path("test")
public static class TestResource {
private final IDao dao;
@Inject
public TestResource(IDao dao) {
this.dao = dao;
}
@GET
public String get() {
return dao.get();
}
}
private static class Mapper implements ExceptionMapper<Throwable> {
@Override
public Response toResponse(Throwable ex) {
ex.printStackTrace(System.err);
return Response.serverError().build();
}
}
@Override
public ResourceConfig configure() {
return new ResourceConfig(TestResource.class)
.register(new PersistenceBinder())
.register(new Mapper())
.register(new LoggingFilter(Logger.getAnonymousLogger(), true));
}
@Test
public void shouldReturnEnglish() {
final Response response = target("test").queryParam("lang", "en").request().get();
assertEquals(200, response.getStatus());
assertEquals("English", response.readEntity(String.class));
}
@Test
public void shouldReturnFrench() {
final Response response = target("test").queryParam("lang", "fr").request().get();
assertEquals(200, response.getStatus());
assertEquals("French", response.readEntity(String.class));
}
}
もう1つのことは、SessionFactory
のクローズです。 Factory
にはdispose()
メソッドがありますが、確実にJerseyによって呼び出されるわけではありません。 ApplicationEventListener
を調べることができます。 SessionFactory
をその中に注入して、クローズイベントでそれらをシャットダウンすることができます。
どのジャージーバージョンを使用していますか? –
ジャージー2.19を使用しています。未成年者を時々更新します – vvondra