我正在使用存储String的ThreadLocal对象。我将String值设置为过滤器中的ThreadLocal对象,该对象拦截受特定条件限制的所有请求。另外,我将ThreadLocal的字符串值设置为HttpSession作为属性。
会话中的属性用于多个jsps,最终传递给业务层。
我面临的问题是,来自不同客户端的多个请求在某个时间点获得相同的字符串值,尽管会话不同。
所以我的理解是,多个会话访问同一个线程。我没有看到任何其他解释。
在jsps之间移动时,将属性设置为请求会导致问题。由于弹簧安全性存在重定向,这意味着请求属性丢失。
那么有什么方法可以改变实现,以便多个会话不使用相同的线程?
编辑:添加示例代码
public class ContextFilter implements Filter {
//No significant variables other than constants
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// Set the Session Timeout Object
SessionTimeoutObject obj = (SessionTimeoutObject) httpRequest
.getSession().getAttribute(KEY);
if (obj == null) {
httpRequest.getSession().setAttribute(KEY,
new SessionTimeoutObject());
}
if( some conditions ) {
chain.doFilter(request, response);
} else {
//Defaulting identifier
String identifier = "init";
if (ContextHolder.getId() != null
&& !ContextHolder.getId().equals("")) {
identifier = ContextHolder.getId());
}
//Do some thing
//Compare the identifier with the value in session and use if it exists
String existingId = (String) httpRequest.getSession()
.getAttribute(ID_KEY);
if (existingId != null
&& !existingId.trim().equals("")) {
identifier = existingId;
}
//Setting id to context only happens here
ContextHolder.setId(identifier);
//Validate the identifier
//Get Business Obj method using identifier
BusinessObj bo = getBusObj(identifier);
//everything above is successful so set in session
httpRequest.getSession().setAttribute("identifier", identifier);
httpRequest.getSession().setAttribute("BusinessObj",
bo);
//no exceptions yet then good to go
chain.doFilter(request, response);
}
}
}
public class SessionTimeoutObject implements Serializable, HttpSessionBindingListener {
private String backup;
@Override
public void valueBound(HttpSessionBindingEvent event) {
//Mainly for debuggin what happens to the session
backup = (String) event.getSession().getAttribute("identifier");
}
@Override
public void valueUnbound(HttpSessionBindingEvent event) {
//Mainly for debuggin what happens to the session
if (ContextHolder.getId() != null) {
backup = ContextHolder.getId();
}
}
}
class ContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public ContextHolder() {
}
public static void setId(String identifier) {
if (null == identifier) {
//throw some exception
}
contextHolder.set(identifier);
}
public static String getId() {
return (String) contextHolder.get();
}
public static void clearId() {
contextHolder.remove();
}
public static void setDefaultId() {
ContextHolder.clearId();
contextHolder.set('init');
}
}
答案 0 :(得分:1)
你应该将你的代码包装在try / finally块中,在finally块中执行一个清除上下文持有者的ContextHolder.clearId()。这很重要,因为请求处理线程被重用,这意味着ContextHolders线程本地保留与以前相同的id。 - M. Deinum
做到这一点解决了这个问题。