0
点赞
收藏
分享

微信扫一扫

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解决方案​​


举报

相关推荐

0 条评论