我正在研究一个凌乱的Struts 1应用程序,它利用自定义上下文类来存储整个应用程序的值。基本上它只用于存储会话范围变量。我猜想使用这个自定义类的原因是为了让其他没有访问http会话的类仍然可以获取和设置会话变量。ThreadLocale值在Servlet筛选器中混合起来
不管怎么说,大多数情况下,这工作得很好。自定义上下文在动作和服务类中用于共享变量,没有任何问题。但是,我刚发现,在Http过滤器中使用这个自定义上下文并不能很好地工作!看起来,它随机会从不同的会话中提取值。而通过会话,我实际上是指线程,因为这个自定义上下文使用ThreadLocale来完成它的肮脏工作。
看看
package com.zero.alpha.common;
import java.io.Serializable;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Map;
public final class CustomContext implements Serializable {
private static final long serialVersionUID = 400312938676062620L;
private static ThreadLocal<CustomContext> local = new ThreadLocal() {
protected CustomContext initialValue() {
return new CustomContext("0", "0", Locale.getDefault());
}
};
private String dscId;
private String sessionId;
private Locale locale;
private Map<String, Serializable> generalArea;
public CustomContext(String dscId, String sessionId, Locale locale) {
this.dscId = dscId;
this.sessionId = sessionId;
if (locale != null) {
this.locale = locale;
} else {
this.locale = Locale.getDefault();
}
this.generalArea = new Hashtable();
}
public static CustomContext get() {
return ((CustomContext) local.get());
}
public static void set(CustomContext context) {
local.set(context);
}
public String getDscId() {
return this.dscId;
}
public String getSessionId() {
return this.sessionId;
}
public Locale getLocale() {
return this.locale;
}
public Serializable getGeneralArea(String key) {
return ((Serializable) this.generalArea.get(key));
}
public Serializable putGeneralArea(String key, Serializable value) {
return ((Serializable) this.generalArea.put(key, value));
}
public void clearGeneralArea() {
this.generalArea.clear();
}
public Serializable removeGeneralArea(String key) {
return ((Serializable) this.generalArea.remove(key));
}
}
同样,这似乎工作很好,很正常,不是一个过滤器等所有其他类中。让我向你展示过滤器在哪里混乱。
package com.zero.alpha.myapp.common.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.zero.alpha.common.CustomContext;
import com.zero.alpha.myapp.utility.CommonConstants;
import com.zero.alpha.myapp.utility.CommonHelpers;
import com.zero.alpha.myapp.UserDomain;
public class LoginFilter implements Filter {
public LoginFilter() {
}
public void init(FilterConfig config) throws ServletException {}
public void destroy() {}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
// Don't use the login filter during a login or logout request
if (req.getServletPath().equals("/login.do")
|| req.getServletPath().equals("/login-submit.do")
|| req.getServletPath().equals("/logout.do")) {
chain.doFilter(request, response);
} else {
doFilter(req, (HttpServletResponse) response, chain);
}
}
protected void doFilter(HttpServletRequest request, HttpServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpSession session = request.getSession(false);
// This is the problem right here. Sometimes this will grab the value of a different user currently logged in
UserDomain user = (UserDomain) CustomContext.get()
.getGeneralArea(CommonConstants.ContextKey.USER_SESSION);
if (session == null || user == null) {
// Unauthorized
response.sendRedirect(loginPage);
} else {
// Authorized
session.setAttribute("userInfo", CommonHelpers.getUserDisplay(user));
chain.doFilter(request, response);
}
}
}
当自定义上下文用于抓住在doFilter方法的用户,它会随机抓住从另一登录用户的用户对象。显然不是一个好的情况!
发生这种情况的唯一时间是来自不同登录用户的一些活动。我可以整天坐在那里,并保持刷新用户A的会议,并没有问题。但是,在以用户B的身份采取某些措施并再次刷新用户A的会话之后,通常会进行交换。但是,如果我再次刷新用户A的会话,事情就会恢复正常。
我注意到,当应用程序实际部署到远程开发tomcat服务器时,发生这种情况的频率非常高。它在本地运行时仍然会发生,但几乎不如远程部署时那么频繁。它远程发生几乎100%的时间。
我已经检查过滤器内部的会话变量,并且会话本身没有出现问题。我已经确认,即使从ThreadLocale变量中拉取不正确的用户,会话ID仍然正确。
任何人都可以帮我吗?谢谢。
您确定用户b操作不访问自定义上下文实例吗? – efekctive
@efekctive用户B的操作确实使用与用户A相同的自定义上下文。 – zero01alpha