2012-12-19 28 views
0

我曾經有一個基於Cookie的JSF 2應用程序中的對話中的開放會話。現在我想建立相同的機制,但技術不可知論者。重用一些代碼,我一直在擴展OncePerRequestFilter類寫成這樣:訪問任何地方的HttpServletRequest

@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的,過濾器可以被調用作爲請求或發生在單獨的線程 ASYNC調度的一部分。在web.xml中配置的過濾器可以是 ,它是否應該參與異步 調度。但是,在某些情況下,servlet容器會採用不同的 默認配置。因此,子類可以重寫方法 shouldNotFilterAsyncDispatch()靜態聲明,如果它們確實被調用,那麼在這兩種類型的調度期間,爲了 提供了線程初始化,日誌記錄,安全等等。此 機制補充並且不取代在web.xml中使用調度程序類型配置 過濾器的需要。

那麼,使用ThreadLocal來達到我想要的效果會很危險嗎?

+0

ThreadLocal是JSF使用的,因此不應該是危險的。 JSF可以做它做的事情,因爲所有事情都是通過儀器可能發生的單一FacesServlet進行路由。如果你想做類似的事情,你必須使用類似的策略。 – Gimby

+0

是的,但是如果過濾器配置了ASYNC分派,許多線程將使用該機制。除非這些線程是從運行bindConversation代碼的線程派生的,否則我將得到NullPointerExceptions。不是嗎?此外,清理會很棘手,因爲如果我將請求放入InheritableThreadLocal中,容器可能會使用一個池並導致問題? – ElderMael

回答

1

正如你在你的問題中提到的:使用ThreadLocal似乎是一個不錯的選擇。我不明白爲什麼在您對REQUEST和ASYNC同時使用過濾器時它會很不安全。

EDIT

@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(...)期間從它獲得的值將是正確的。 (除非您在請求處理期間手工創建新線程,但它不是推薦設計)

+1

我很關心清理問題,因爲javadoc明確指出了Servlet 3中引入的調度器類型javax.servlet.DispatcherType.ASYNC。0表示濾波器可以在多個線程在單個request.' – ElderMael

+0

的過程中調用剛纔編輯我的職務與一些代碼 – ben75

+0

差不多我在想什麼,它看起來像一個HibernateTransactionManager但是伴隨許多請求一個會話! – ElderMael

相關問題