2.SpringSession源码:流程中几个重要方法

2.SpringSession源码:流程中几个重要方法

Posted by ZhaoLe on May 7, 2019

接着上篇文章从SessionRepositoryFilter.java开始说起。之前说SessionRepositoryFilter过滤器将request和response封装成自己定义的类型。所以用户代码request.getSession()其实调用到的是SessionRepositoryRequestWrapper中已经被重写了的getSession()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//SessionRepositoryFilter
@Override
public HttpSessionWrapper getSession(boolean create) {
    HttpSessionWrapper currentSession = getCurrentSession();
    if (currentSession != null) {
        return currentSession;
    }
    S requestedSession = getRequestedSession();
    if (requestedSession != null) {
        if (getAttribute(INVALID_SESSION_ID_ATTR) == null) {
            requestedSession.setLastAccessedTime(Instant.now());
            this.requestedSessionIdValid = true;
            currentSession = new HttpSessionWrapper(requestedSession, getServletContext());
            currentSession.setNew(false);
            setCurrentSession(currentSession);
            return currentSession;
        }
    }
    else {
        if (SESSION_LOGGER.isDebugEnabled()) {
            SESSION_LOGGER.debug(...);
        }
        setAttribute(INVALID_SESSION_ID_ATTR, "true");
    }
    if (!create) {
        return null;
    }
    if (SESSION_LOGGER.isDebugEnabled()) {
        SESSION_LOGGER.debug(...);
    }
    S session = SessionRepositoryFilter.this.sessionRepository.createSession();
    session.setLastAccessedTime(Instant.now());
    currentSession = new HttpSessionWrapper(session, getServletContext());
    setCurrentSession(currentSession);
    return currentSession;
}
  • 【4】 getCurrentSession()先根据名称从request中获取session,同一个请求中,session如果存在就直接获取,不需要再从存储中获取了

    1
    2
    3
    
      private HttpSessionWrapper getCurrentSession() {
          return (HttpSessionWrapper) getAttribute(CURRENT_SESSION_ATTR);
      }
    
  • 【8】 getRequestedSession()从缓存中获取session,具体参照【2.1.SpringSession源码:getRequestedSession】
  • 【9-18】获取session成功后(此时的RequestedSession类型),包装成HttpSessionWrapper类型,如果继续个跟进代码会发现 这些都是在HttpSessionAdapter.java适配器中进行的。然后调用setCurrentSession放回当前的请求中
  • 【31】createSession() ,如果request和redis中都没有session 就要新创建一个了。 具体参照【2.2SpringSession源码:createSession()】
  • 【32-34】在RedisSession基础上再次封装下,然后存入当前请求中

最后在SessionRepositoryFilter.java里面的doFilterInternal方法里有个commitSession方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//SessionRepositoryFilter.java
private void commitSession() {
    HttpSessionWrapper wrappedSession = getCurrentSession();
    if (wrappedSession == null) {
        if (isInvalidateClientSession()) {
            SessionRepositoryFilter.this.httpSessionIdResolver.expireSession(this,
                    this.response);
        }
    }
    else {
        S session = wrappedSession.getSession();
        clearRequestedSessionCache();
        SessionRepositoryFilter.this.sessionRepository.save(session);
        String sessionId = session.getId();
        if (!isRequestedSessionIdValid()
                || !sessionId.equals(getRequestedSessionId())) {
            SessionRepositoryFilter.this.httpSessionIdResolver.setSessionId(this,
                    this.response, sessionId);
        }
    }
}
  • 【3】直接从当前请求中获取session
  • 【4-9】如果不存在,检查是否失效,如果失效就调用CookieHttpSessionIdResolver#expireSession将对应的Cookie值设置为空并写回响应
  • 【12】finally阶段,清除掉一些缓存标记,初始化一些成员变量
  • 【13】在RedisOperationsSessionRepository#save中实现,用于持久化,其中session.saveDelta();的调用在【2.2SpringSession源码:createSession()】已经说明了
  • 【14-19】在CookieHttpSessionIdResolver#setSessionId将sessionId写回response给客户端.