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,如果是则会删除