...インスタンスを手動で構築する必要がある場合、たとえばサードパーティのファクトリ クラスによって構築する必要がある場合はどうでしょうか? 以前 (Jersey 1.x) は、次のようにしていました。
public class MyInjectableProvider extends PerRequestTypeInjectableProvider<Context, MyInjectable> {
public MyInjectableProvider() {
super(MyInjectable.class);
}
@Override
public Injectable<MyInjectable> getInjectable(ComponentContext ic, Context context) {
MyInjectable myInjectableInstance = //...
return new Injectable<MyInjectable>() {
@Override
public MyInjectable getValue() {
return myInjectableInstance;
}
};
}
}
匿名ローカル クラスは、インスタンスにアクセスして、あるスコープ内で返すことができます。これは、デフォルトのコンストラクターを持つクラスを操作していないが、リクエストごとに構築する必要がある場合に便利です。
Jersey 2.0は依存性注入フレームワークとしてHK2に切り替えましたが、残念ながら移行ページ(移行) では、この種のバインディングの例は提供されておらず、HK2 のドキュメントでは AbstractBinder を使用する例は提供されていません。
もう少し詳しく説明すると、リソースローカルでコンテナに依存しない JPA EntityManager インスタンスをリソースに提供しようとしています。これらはシングルトン ファクトリ クラスから取得する必要があり、単一の「作業単位」の間だけ存在する必要があります。これは私の場合の要求です。回避策があることは承知していますが (ファクトリを挿入するか、スレッドローカルにバインドするだけ)、以前のソリューションが優れていると感じたので、可能であればそれを再現したいと思います。
編集:
HK2 の javadocs を少し調べたところ、次のようにして同様のことが実現できることがわかりました。
public class MyInjectableProvider extends AbstractBinder
implements Factory<MyInjectable> {
@Override
protected void configure() {
bindFactory(this).to(MyInjectable.class);
}
@Override
public MyInjectable provide() {
return getMyInjectable();
}
@Override
public void dispose(MyInjectable instance) {}
}
そしてそれを登録するには...
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
register(new MyInjectableProvider());
}
}
これは「動作するようだ」が、少し不明瞭なようにも思えます。たとえば、dispose() は呼び出されません。また、このバインディングは暗黙的に RequestScoped として動作するようです。構成を変更しても、bindFactory(this).to(MyInjectable.class).in(RequestScoped.class);
動作は実際には変更されないようです。何か見落としているのでしょうか、それともこれが意図された解決策なのでしょうか?
ベストアンサー1
の代わりにFactory<T>.dispose(T)
、インジェクタブルを使用して登録すると、CloseableService
必要なことのほとんどを実行できます。CloseableFactory
アダプタが必要になります。CloseableService
closes()
リクエスト スコープを終了すると、登録されているすべてのリソースが削除されます。
具体的な例についてはConnectionFactory
以下を参照してください。
import org.glassfish.hk2.api.Factory;
import org.glassfish.jersey.server.CloseableService;
import javax.inject.Inject;
import javax.ws.rs.InternalServerErrorException;
import java.sql.Connection;
import java.sql.SQLException;
import static com.google.common.base.Preconditions.checkNotNull;
public class ConnectionFactory implements Factory<Connection> {
private final CloseableService closeableService;
@Inject
public ConnectionFactory(CloseableService closeableService) {
this.closeableService = checkNotNull(closeableService);
}
public Connection provide() {
final Connection connection;
try {
connection = acquireConnection();
} catch (SQLException e) {
throw new InternalServerErrorException(e);
}
try {
closeableService.add(new CloseableConnection(connection));
} catch (Throwable t) {
closeQuietly(connection);
throw runtime(t);
}
return connection;
}
public void dispose(Connection connection) {
closeQuietly(connection);
}
private static RuntimeException runtime(Throwable t) {
throw ConnectionFactory.<RuntimeException>unchecked(t);
}
private static <T extends Throwable> T unchecked(Throwable t) throws T {
throw (T) t;
}
private static void closeQuietly(Connection connection) {
try {
connection.close();
} catch (SQLException ignore) {}
}
}
CloseableFactory
以下は、 a - aのあまり一般的ではないバージョンですCloseableConnection
。
import java.io.Closeable;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import static com.google.common.base.Preconditions.checkNotNull;
public final class CloseableConnection implements Closeable {
private final Connection connection;
public CloseableConnection(Connection connection) {
this.connection = checkNotNull(connection);
}
public void close() throws IOException {
try {
connection.close();
} catch (SQLException e) {
throw new IOException(e);
}
}
}