spring session的生命周期
Session获取
spring-session实现了HttpServletRequest的子类–SessionRepositoryRequestWrapper,由它覆盖getSession方法,将由web容器处理的逻辑接管过来。
public HttpSession getSession(boolean create) {
HttpSessionWrapper currentSession = getCurrentSession();
if(currentSession != null) {
return currentSession;
}
String requestedSessionId = getRequestedSessionId();
if(requestedSessionId != null) {
S session = sessionRepository.getSession(requestedSessionId);
if(session != null) {
this.requestedSessionIdValid = true;
currentSession = new HttpSessionWrapper(session, getServletContext());
//从数据仓库提取出来的session状态不为new
currentSession.setNew(false);
setCurrentSession(currentSession);
return currentSession;
}
}
if(!create) {
return null;
}
S session = sessionRepository.createSession();
currentSession = new HttpSessionWrapper(session, getServletContext());
setCurrentSession(currentSession);
return currentSession;
}
session id存在的情况下,如果通过session id能找到持久化的session就直接返回,否则根据create是否为true决定是否新建一个Session。Session在后续的使用中会陆续更改,添加、删除或者修改属性值。从数据仓库中提取出来的session会默认修改lastAccessTime属性以避免session失效。
数据仓库中的持久化session也存在失效时间,消费端可以通过RedisHttpSessionConfiguration.setMaxInactiveIntervalInSeconds(long timemills)来设置,默认是1800秒。redis会定时清除过期数据。
spring-session的Session实现
Spring为了将Session与具体的协议分开,单独提炼出Session实体,再通过HttpSessionWrapper将session包装起来,从而扩展HttpSession.如果以后还需要支持另外一种应用协议,就只要增加一种应用类型的wrapper就行了。
private final class HttpSessionWrapper implements HttpSession {
public HttpSessionWrapper(S session, ServletContext servletContext) {
this.session = session;
this.servletContext = servletContext;
}
//省略了大部分方法,都是委托给被包装的Session处理的
//对session坐invalidate时去数据仓库删掉对应的数据
public void invalidate() {
checkState();
this.invalidated = true;
requestedSessionInvalidated = true;
setCurrentSession(null);
sessionRepository.delete(getId());
}
public void setNew(boolean isNew) {
this.old = !isNew;
}
public boolean isNew() {
checkState();
return !old;
}
}
}
Session实体主要定义通用的getAttribute和setAttribute等方法。此外扩展了一个ExpiringSession,这是spring的默认session,它主要用来判断session是否失效。
public interface ExpiringSession extends Session {
//session的创建时间
long getCreationTime();
//session的上次访问时间
long getLastAccessedTime();
//设置最大访问间隔,超过这个间隔session会被invalidate
void setMaxInactiveIntervalInSeconds(int interval);
int getMaxInactiveIntervalInSeconds();
//session是否失效
boolean isExpired();
}
session提交
private void commitSession() {
HttpSessionWrapper wrappedSession = getCurrentSession();
if(wrappedSession == null) {
if(isInvalidateClientSession()) {
httpSessionStrategy.onInvalidateSession(this, response);
}
} else {
S session = wrappedSession.session;
sessionRepository.save(session);
if(!isRequestedSessionIdValid() || !session.getId().equals(getRequestedSessionId())) {
httpSessionStrategy.onNewSession(session, this, response);
}
}
}
- getSession时会通过setCurrentSession把新建或者提取出来的session放到request的HttpServletRequestWrapper.class.getName()属性上;相应的在session invalidate时也会将session从request里移除掉,此时通过getCurrentSession将取不到数据。
- 在做session持久化时,会首先判断session是否被invalidate,如果是则会删除