2

我正在编写一个允许人们协作的 Web 应用程序。我希望我的一些服务范围仅限于协作(涉及几个人),而不是任何单独的 http 会话。我创建了一个Scope存储 bean 的自定义。为了管理 bean 生命周期,我跟踪关联的会话 ID,如下所示:

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. 如果我可以访问HttpSession中的Scope,我可以将 添加Scope到存储在会话中的列表中,并让侦听器通知该列表的成员会话即将结束。但是我看不到如何在Scope实例中获取会话对象(而不仅仅是它的 id)。

  3. 我可以让我Scope实现HttpSessionListener接口,从而直接更新它的状态,但我不知道如何以编程方式注册一个监听器。有没有公​​开的方式来做到这一点?

  4. 有没有更好的办法?

谢谢你的帮助,

基因

4

1 回答 1

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);
}

但是,我不清楚何时ScopeSessionMonitor. 会 WeakArray在这里工作吗?

于 2011-11-18T21:58:45.517 回答