2013-08-29 4 views
1

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'); 
    } 
} 
+0

나는 여러 세션이 동시에 같은 스레드를 사용하는지 의심 스럽다. 나는 그것이 사용 된 후에 자원 (ThreadLocal)을 정리하지 않는 문제라고 생각한다. 코드를 필터에 게시 할 수 있습니까? 또한 참조를 어딘가에 싱글 톤에 저장하지 않도록하십시오. –

+0

당신이 옳을 수도 있습니다, 나는 자원을 정리하는 것에 대해 더 살펴볼 것입니다. 샘플 코드도 추가했습니다. '싱글 톤에 레퍼런스를 저장하지 마십시오'와 관련하여 나는 그것을 이해하고 있는지 확신 할 수 없다. ContextHolder를 살펴보고, 나는 다른 많은 장소에서 식별자를 필요로하며, 컨텍스트 홀더에 의존한다. – BST

+1

try/finally 블록에 코드를 래핑해야합니다. finally 블록에서는 컨텍스트 보유자를 지우는 ContextHolder.clearId()를 호출해야합니다. 이는 요청 처리 스레드가 재사용되고 'ContextHolder' 스레드 로컬이 이전과 동일한 ID를 유지한다는 것을 의미하므로 중요합니다. –

답변

1

컨텍스트 홀더를 지우는 ContextHolder.clearId()를 않습니다. 이는 요청 처리 스레드가 재사용되고 ContextHolders 스레드 로컬이 이전과 동일한 ID를 유지함을 의미하므로 중요합니다. - M. Deinum

위의 작업을 수행하면 문제가 해결됩니다.