我正在编写一个允许人们进行协作的Web应用程序。我希望我的一些服务范围包括协作(涉及少数人),而不是任何单独的http会话。我创建了一个存储bean的自定义Scope
。为了管理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
和监听器之间存在脱节。我看到了以下几种可能性:
我可以静态创建HttpSessionListener
,假设一个唯一的实例,让它管理订阅列表,让我的Scope
个实例订阅它的事件。但这似乎是多余的,我不喜欢单身模式。
如果我有权访问HttpSession
中的Scope
,我可以将Scope
添加到会话中存储的列表中,并让监听器通知成员会话即将消失的列表。但我不知道如何在Scope
实例中获取会话对象(而不仅仅是其id)。
我可以让Scope
实现HttpSessionListener
接口,从而直接更新其状态,但我不知道如何以编程方式注册监听器。有没有公开的方式呢?
有更好的方法吗?
感谢您的帮助,
基因
答案 0 :(得分: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);
}
但是,我不清楚何时从Scope
移除SessionMonitor
。某种WeakArray
会在这里工作吗?