我正在研究一個凌亂的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