0

以前は、JSF 2 アプリの Cookie に基づく Open Session In Conversation フィルターを使用していました。今、私は同じメカニズムを構築したいと考えていますが、テクノロジーに依存しません。いくつかのコードを再利用して、これをOncePerRequestFilterを拡張するクラスに記述しました。

@Override
protected void doFilterInternal(HttpServletRequest request,
        HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {

    UUID conversationId = lookupConversationOrCreateIfNecessary(request,
            response);

    log.debug("Binding conversation '{}' to request '{}'", conversationId,
            request);
    bindConversation(conversationId, request);

    try {
        filterChain.doFilter(request, response);
    } finally {
        log.debug("Unbinding conversation '{}' from request '{}'",
                conversationId, request);
        unbindConversation(conversationId, request);
    }

}

今、到達したら、 Hibernate SessionbindConversation(conversationId, request)にマップされている conversationId を指す request 属性を追加するだけです。

とにかく、JSF では、これを使用してCurrentSessionContextFacesContext.getCurrentInstance().getExternalContext().getRequest()を使用して実装することで、現在のリクエストにアクセスできます。しかし、単純なサーブレットでは、現在のリクエストにプログラムでアクセスするにはどうすればよいでしょうか?

注: 私は OncePerRequestFilter javadocs を読んでいて、これを見つけました:

Servlet 3.0 では、別のスレッドで発生する REQUEST または ASYNC ディスパッチの一部としてフィルタを呼び出すことができます。フィルターは、非同期ディスパッチに関与する必要があるかどうかを web.xml で構成できます。ただし、場合によっては、サーブレット コンテナーが異なるデフォルト構成を前提とします。したがって、サブクラスは、メソッド shouldNotFilterAsyncDispatch() をオーバーライドして、スレッドの初期化、ロギング、セキュリティなどを提供するために両方のタイプのディスパッチ中に [sic] 実際に 1 回呼び出す必要がある場合、静的に宣言できます。このメカニズムは、web.xml でフィルターをディスパッチャー タイプで構成する必要性を補完し、置き換えるものではありません。

では、 ThreadLocalを使用して目的を達成するのは危険でしょうか?

4

1 に答える 1

1

あなたの質問で言及したように、 ThreadLocal を使用することは良い選択肢のようです。REQUEST と ASYNC の両方にフィルターを使用するとすぐに安全でなくなる理由がわかりません。

編集

@Override
protected void doFilterInternal(HttpServletRequest request,
                                HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {


    UUID conversationId = lookupConversationOrCreateIfNecessary(request,
            response);

    log.debug("Binding conversation '{}' to request '{}'", conversationId,
            request);

    ConversationHolder.setId(conversationId);

    bindConversation(conversationId, request);

    try {
        filterChain.doFilter(request, response);
    } finally {
        log.debug("Unbinding conversation '{}' from request '{}'",
                conversationId, request);
        ConversationHolder.clear();
        unbindConversation(conversationId, request);
    }

}

@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
    return false; //to be sure both REQUEST and ASYNC are filtered
}

そして、ConversationHolder

public class ConversationHolder extends ThreadLocal<UUID>{

    private static ConversationHolder INSTANCE = new ConversationHolder();

    public static void setId(UUID conversationId){
          INSTANCE.set(conversationId);
    }

    public static UUID getId(){
        return INSTANCE.get();
    }

    public static void clear(){
        INSTANCE.remove();
    }

}

conversationId はローカル変数であるため、リクエスト間で共有されません。

ConversationHolder は ThreadLocal であるため、doFilter(...) 中に取得する値は正しいものになります。(ただし、リクエスト処理中に手動で新しいスレッドを作成する場合を除きますが、推奨される設計ではありません)

于 2012-12-19T15:51:41.203 に答える