2011-11-16 71 views
2

我正在編寫一個允許人們協作的Web應用程序。我希望將我的一些服務範圍擴展到協作(涉及少數人),而不是任何單個的http會話。我創建了一個存儲bean的自定義Scope。爲了管理bean的生命週期,我把相關的會話ID的軌跡如下:將範圍連接到HttpSessionListener

protected ConcurrentMap<String,Object> attributes = 
    new ConcurrentHashMap<String, Object>(); 

... 
@Override 
public Object get(String name, ObjectFactory<?> factory) { 
    synchronized(this.attributes) { 
     Object scopedObject = this.attributes.get(name); 
     if (scopedObject == null) { 
      scopedObject = factory.getObject(); 
      this.attributes.put(name, scopedObject); 
      RequestAttributes reqAttrs = RequestContextHolder.currentRequestAttributes(); 
      activeSession(name).add(reqAttrs.getSessionId()); 

     } 
     return scopedObject; 
    } 
} 

在關閉會話時,我想從與給定的bean名字相關聯的活動會話列表中刪除會話ID。當設定變空時,我可以清理。

我能想到管理會話關閉的最簡單方法是使用HttpSessionListener,但我的Scope與監聽器之間斷開連接。我看到了以下可能性:

  1. 我可以創建HttpSessionListener靜態,假設一個單一實例,把它管理訂閱列表,並有我Scope實例訂閱其事件。但這似乎是多餘的,我不喜歡這種單身模式。

  2. 如果我在Scope不得不進入HttpSession,我可以在Scope添加到存儲在會話列表,並有聽衆通知列表,該會議即將離開的成員。但我不明白如何在Scope實例中使用會話對象(而不僅僅是它的id)。

  3. 我可以讓我的Scope實現HttpSessionListener接口,從而直接更新其狀態,但我不知道如何以編程方式註冊偵聽器。有沒有公​​開的方式來做到這一點?

  4. 有沒有更好的方法?

感謝您的幫助,

基因

+0

有一個[相關的問題](http://stackoverflow.com/questions/2433321/how-to-inject-dependencies-into-httpsessionlistener-using-spring)有一個更「春天」的解決方案。 – Eyal

回答

2

沒有收到任何意見或答案,我與選項#1去了,如下:

public class SessionMonitor implements HttpSessionListener { 
    protected final Log logger = LogFactory.getLog(getClass()); 

    protected CopyOnWriteArrayList<SessionEventListener> subscribers = new CopyOnWriteArrayList<SessionEventListener>(); 
    protected ConcurrentHashMap<String,HttpSession> sessions = new ConcurrentHashMap<String,HttpSession>(); 
    protected static SessionMonitor singleton; 
    public static SessionMonitor soleInstance() throws ConfigurationException { 
     if (singleton == null) 
      throw new ConfigurationException("No SessionMonitor instance has been created"); 
     return singleton; 
    } 

    public SessionMonitor() { 
     if (singleton == null) 
      singleton = this; 
    } 

    @Override 
    public void sessionCreated(HttpSessionEvent e) { 
     HttpSession session = e.getSession(); 
     this.sessions.putIfAbsent(session.getId(), session); 
     logger.trace("Registered session " + session.getId()); 
    } 

    @Override 
    public void sessionDestroyed(HttpSessionEvent e) { 
     String sessionId = e.getSession().getId(); 
     this.sessions.remove(sessionId); 
     for (SessionEventListener listener: subscribers) 
      listener.sessionEnded(sessionId); 
     logger.trace("Removed session " + sessionId); 
    } 

    public HttpSession getSession(String id) { 
     return this.sessions.get(id); 
    } 

    public void addListener(SessionEventListener listener) { 
     this.subscribers.add(listener); 
     logger.trace("Added listener " + listener); 
    } 

    public void removeListener(SessionEventListener listener) { 
     this.subscribers.remove(listener); 
     logger.trace("Removed listener " + listener); 
    } 
} 

當範圍變創建後,它將自己註冊爲SessionMonitor

public ConditionalScope() throws ConfigurationException { 
    logger.debug("Registering " + this.toString() + " for session monitoring"); 
    SessionMonitor.soleInstance().addListener(this); 
} 

但是,我不清楚何時從SessionMonitor中刪除Scope。某種WeakArray會在這裏工作嗎?