Jersey 2.0を使用して、リクエストごとにバインド可能なインスタンスを登録するにはどうすればよいですか? 質問する

Jersey 2.0を使用して、リクエストごとにバインド可能なインスタンスを登録するにはどうすればよいですか? 質問する

...インスタンスを手動で構築する必要がある場合、たとえばサードパーティのファクトリ クラスによって構築する必要がある場合はどうでしょうか? 以前 (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);
        }
    }
}

おすすめ記事