我以前在基于Cookie的JSF 2应用程序的对话过滤器中有一个Open Session。现在我想建立相同的机制,但技术无关。重用一些代码,我在一个扩展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容器会有所不同 默认配置。因此子类可以覆盖该方法 如果他们[sic] shouuld,则shouldNotFilterAsyncDispatch()静态声明 确实可以在两种类型的调度期间调用一次 提供线程初始化,日志记录,安全性等。这个 机制补充并不代替配置的需要 在带有调度程序类型的web.xml中进行过滤。
那么,使用ThreadLocal来实现我想要的东西会是危险的吗?
答案 0 :(得分: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(...)期间从中获取的值将是正确的。 (除非您在请求处理期间手动创建新线程,但它不是推荐的设计)