String을 저장하는 ThreadLocal 객체를 사용하고 있습니다. 특정 조건에 따라 모든 요청을 차단하는 필터의 ThreadLocal 객체에 문자열 값을 설정합니다. 또한 ThreadLocal의 문자열 값을 특성으로 HttpSession에 설정하고 있습니다.Filter, HttpSession 및 Session 속성이있는 ThreadLocal을 사용하는 동안 불일치가 발생합니다.
세션의 속성은 여러 jsp에서 사용되며 결국 비즈니스 계층으로 전달됩니다.
내가 직면 한 문제는 세션이 다르더라도 다른 클라이언트에서 발생하는 여러 요청이 어느 시점에서 동일한 문자열 값을 갖게된다는 것입니다.
제 생각에 여러 세션이 동일한 스레드에 액세스합니다. 나는 이것에 대한 다른 설명을 보지 못했다.
요청에 속성을 설정하면 jsp간에 이동할 때 문제가 발생합니다. 스프링 보안에 의한 리다이렉션이 있기 때문에 요청 속성이 상실된다.
그래서 여러 세션에서 같은 스레드를 사용하지 않도록 구현을 변경할 수있는 방법이 있습니까?
편집 : 추가 샘플 코드 당신은 마지막으로 차단하려면에,/finally 블록 시도에 코드를 포장해야
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');
}
}
나는 여러 세션이 동시에 같은 스레드를 사용하는지 의심 스럽다. 나는 그것이 사용 된 후에 자원 (ThreadLocal)을 정리하지 않는 문제라고 생각한다. 코드를 필터에 게시 할 수 있습니까? 또한 참조를 어딘가에 싱글 톤에 저장하지 않도록하십시오. –
당신이 옳을 수도 있습니다, 나는 자원을 정리하는 것에 대해 더 살펴볼 것입니다. 샘플 코드도 추가했습니다. '싱글 톤에 레퍼런스를 저장하지 마십시오'와 관련하여 나는 그것을 이해하고 있는지 확신 할 수 없다. ContextHolder를 살펴보고, 나는 다른 많은 장소에서 식별자를 필요로하며, 컨텍스트 홀더에 의존한다. – BST
try/finally 블록에 코드를 래핑해야합니다. finally 블록에서는 컨텍스트 보유자를 지우는 ContextHolder.clearId()를 호출해야합니다. 이는 요청 처리 스레드가 재사용되고 'ContextHolder' 스레드 로컬이 이전과 동일한 ID를 유지한다는 것을 의미하므로 중요합니다. –