0

我曾经有一个基于 JSF 2 应用程序 cookie 的对话过滤器中的打开会话。现在我想建立相同的机制,但与技术无关。重用一些代码,我在一个扩展了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);
    }

}

现在,当我到达时,bindConversation(conversationId, request)我只需添加一个请求属性,该属性指向映射到 Hibernate Session的 conversationId 。

无论如何,在 JSF 中,我可以使用它来访问当前请求并使用FacesContext.getCurrentInstance().getExternalContext().getRequest()它实现CurrentSessionContext。但是在普通的 servlet 中,我如何以编程方式访问当前请求?

注意:我一直在阅读 OncePerRequestFilter javadocs,我发现了这个:

从 Servlet 3.0 开始,过滤器可以作为 REQUEST 或 ASYNC 调度的一部分被调用,这些调度发生在单独的线程中。可以在 web.xml 中配置过滤器是否应该参与异步调度。但是,在某些情况下,servlet 容器采用不同的默认配置。因此,子类可以重写方法 shouldNotFilterAsyncDispatch() 以静态声明它们 [原文如此] 是否确实应该在两种类型的调度期间被调用一次,以提供线程初始化、日志记录、安全性等。这种机制补充而不是取代在 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 回答