java通过sessionID获取指定session,jetty通过sessionID获取指定session,Jetty的session源码分析
文章目录
- 写在前面
- jetty环境源码分析
- 根据sessionID获取指定Session
- 写在后面
写在前面
session+cookie的机制相信很多小伙伴都明白,这里就不再赘述了。
我们都知道,浏览器请求的信息中会自动将jsessionid传给服务端。
传统方式通过HttpSession session = request.getSession(); 方式就可以获取到一个HttpSession,那么我们如何能通过sessionId来获取到指定用户的session呢?
jetty环境源码分析
本文的运行web环境是jetty环境,tomcat估计同理应该大差不差。
其实,HttpServletRequest、HttpServletResponse、HttpSession不管在jetty、tomcat还是其他web容器中都有一个基本的实现类,而我们通过request.getSession()方式获取session,就是调用了org.eclipse.jetty.server.Request类的getSession()方法:
// org.eclipse.jetty.server.Request#getSession()
/*
* @see javax.servlet.http.HttpServletRequest#getSession()
*/
@Override
public HttpSession getSession()
{
return getSession(true);
}
/*
* @see javax.servlet.http.HttpServletRequest#getSession(boolean)
*/
@Override
public HttpSession getSession(boolean create)
{
if (_session != null)
{
if (_sessionHandler != null && !_sessionHandler.isValid(_session))
_session = null;
else
return _session;
}
if (!create)
return null;
if (getResponse().isCommitted())
throw new IllegalStateException("Response is committed");
if (_sessionHandler == null)
throw new IllegalStateException("No SessionManager");
_session = _sessionHandler.newHttpSession(this); // 创建session
if (_session == null)
throw new IllegalStateException("Create session failed");
HttpCookie cookie = _sessionHandler.getSessionCookie(_session, getContextPath(), isSecure());
if (cookie != null)
_channel.getResponse().replaceCookie(cookie);
return _session;
}
我们可以看到jetty的源码,获取session时进行了判断,如果获取的session为空,就默认新建一个session,创建session是通过_sessionHandler创建的,而_sessionHandler是什么东西呢?
private SessionHandler _sessionHandler;
// org.eclipse.jetty.server.session.SessionHandler#newHttpSession
public HttpSession newHttpSession(HttpServletRequest request)
{
long created = System.currentTimeMillis();
String id = _sessionIdManager.newSessionId(request, created); // 创建sessionid
Session session = _sessionCache.newSession(request, id, created, (_dftMaxIdleSecs > 0 ? _dftMaxIdleSecs * 1000L : -1)); // 创建新的session
session.setExtendedId(_sessionIdManager.getExtendedId(id, request));
session.getSessionData().setLastNode(_sessionIdManager.getWorkerName());
try
{
_sessionCache.add(id, session); // 将session放入缓存
Request baseRequest = Request.getBaseRequest(request);
baseRequest.setSession(session);
baseRequest.enterSession(session);
_sessionsCreatedStats.increment();
if (request != null && request.isSecure())
session.setAttribute(Session.SESSION_CREATED_SECURE, Boolean.TRUE);
callSessionCreatedListeners(session);
return session;
}
catch (Exception e)
{
LOG.warn(e);
return null;
}
}
通过以上源码我们可以看出,session创建完毕后,会将session放入_sessionCache,这个_sessionCache是什么呢?
SessionCache的基本默认实现是DefaultSessionCache,里面存储的session都是用ConcurrentHashMap存储的,key是sessionid,value是session对象:
protected ConcurrentHashMap<String, Session> _sessions = new ConcurrentHashMap<>();
我们继续回到SessionHandler,看着像是session专用的处理器,发现里面有这样一个方法,通过id获取session,正是我们想要的:
// org.eclipse.jetty.server.session.SessionHandler#getSession
public Session getSession(String id)
{
try
{
Session session = _sessionCache.get(id);
if (session != null)
{
//If the session we got back has expired
if (session.isExpiredAt(System.currentTimeMillis()))
{
//Expire the session
try
{
session.invalidate();
}
catch (Exception e)
{
LOG.warn("Invalidating session {} found to be expired when requested", id);
LOG.warn(e);
}
return null;
}
session.setExtendedId(_sessionIdManager.getExtendedId(id, null));
}
return session;
}
catch (UnreadableSessionDataException e)
{
LOG.warn("Error loading session {}", id);
LOG.warn(e);
try
{
//tell id mgr to remove session from all other contexts
getSessionIdManager().invalidateAll(id);
}
catch (Exception x)
{
LOG.warn("Error cross-context invalidating unreadable session {}", id);
LOG.warn(x);
}
return null;
}
catch (Exception other)
{
LOG.warn(other);
return null;
}
}
此时我们只需要能得到这个SessionHandler,就能通过id获取我们想要的session啦!
我发现org.eclipse.jetty.server.Request有个getSessionHandler方法,正好符合我们的预期:
public SessionHandler getSessionHandler()
{
return _sessionHandler;
}
此时大功告成!
根据sessionID获取指定Session
根据上面的分析,我们可以获取我们想要的Session了:
String sessionId = "sessionid";
if(request instanceof org.eclipse.jetty.server.Request){
// 根据sessionId获取指定Session
Session session = ((org.eclipse.jetty.server.Request) request).getSessionHandler().getSession(sessionId);
}
此时我们可以为所欲为了~
写在后面
cookie技术基本算是一个 过时的技术了,很多框架都是通过token+spring session的方式做session共享和前后端登录态的验证。
而spring session更是对session做了进一步的封装,使用起来更加的方便:
spring-session的使用及其原理——分布式session解决方案