spring session源碼解析

  • 2019 年 11 月 11 日
  • 筆記

模塊劃分

core部分代碼

存儲實現部分部分:

jdbc實現

具體存儲的實現類
例如:org.springframework.session.jdbc.JdbcOperationsSessionRepository

支持jdbc訪問的都可以作為存儲介質

JdbcOperationsSessionRepository通過sql來訪問後端存儲:

  private static final String CREATE_SESSION_QUERY = "INSERT INTO %TABLE_NAME%(PRIMARY_ID, SESSION_ID, CREATION_TIME, LAST_ACCESS_TIME, MAX_INACTIVE_INTERVAL, EXPIRY_TIME, PRINCIPAL_NAME) VALUES (?, ?, ?, ?, ?, ?, ?)";    private static final String CREATE_SESSION_ATTRIBUTE_QUERY = "INSERT INTO %TABLE_NAME%_ATTRIBUTES(SESSION_PRIMARY_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES) SELECT PRIMARY_ID, ?, ? FROM %TABLE_NAME% WHERE SESSION_ID = ?";    private static final String GET_SESSION_QUERY = "SELECT S.PRIMARY_ID, S.SESSION_ID, S.CREATION_TIME, S.LAST_ACCESS_TIME, S.MAX_INACTIVE_INTERVAL, SA.ATTRIBUTE_NAME, SA.ATTRIBUTE_BYTES FROM %TABLE_NAME% S LEFT OUTER JOIN %TABLE_NAME%_ATTRIBUTES SA ON S.PRIMARY_ID = SA.SESSION_PRIMARY_ID WHERE S.SESSION_ID = ?";    private static final String UPDATE_SESSION_QUERY = "UPDATE %TABLE_NAME% SET SESSION_ID = ?, LAST_ACCESS_TIME = ?, MAX_INACTIVE_INTERVAL = ?, EXPIRY_TIME = ?, PRINCIPAL_NAME = ? WHERE PRIMARY_ID = ?";    private static final String UPDATE_SESSION_ATTRIBUTE_QUERY = "UPDATE %TABLE_NAME%_ATTRIBUTES SET ATTRIBUTE_BYTES = ? WHERE SESSION_PRIMARY_ID = ? AND ATTRIBUTE_NAME = ?";    private static final String DELETE_SESSION_ATTRIBUTE_QUERY = "DELETE FROM %TABLE_NAME%_ATTRIBUTES WHERE SESSION_PRIMARY_ID = ? AND ATTRIBUTE_NAME = ?";    private static final String DELETE_SESSION_QUERY = "DELETE FROM %TABLE_NAME% WHERE SESSION_ID = ?";    private static final String LIST_SESSIONS_BY_PRINCIPAL_NAME_QUERY = "SELECT S.PRIMARY_ID, S.SESSION_ID, S.CREATION_TIME, S.LAST_ACCESS_TIME, S.MAX_INACTIVE_INTERVAL, SA.ATTRIBUTE_NAME, SA.ATTRIBUTE_BYTES FROM %TABLE_NAME% S LEFT OUTER JOIN %TABLE_NAME%_ATTRIBUTES SA ON S.PRIMARY_ID = SA.SESSION_PRIMARY_ID WHERE S.PRINCIPAL_NAME = ?";    private static final String DELETE_SESSIONS_BY_EXPIRY_TIME_QUERY = "DELETE FROM %TABLE_NAME% WHERE EXPIRY_TIME < ?";

核心流程


org.springframework.session.web.http.OncePerRequestFilter包裝request和response對象

  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {      request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository);      SessionRepositoryFilter<S>.SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryFilter.SessionRepositoryRequestWrapper(request, response, this.servletContext);      SessionRepositoryFilter.SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryFilter.SessionRepositoryResponseWrapper(wrappedRequest, response);        try {        filterChain.doFilter(wrappedRequest, wrappedResponse);      } finally {        wrappedRequest.commitSession();      }      }

org.springframework.session.web.http.SessionRepositoryFilter核心流程:

  • 獲取session如果沒有判斷,是不是因為session無效,無效需要覆蓋掉
    -獲取session如果有,則如果與當前sessionId不同,則需要回寫
  private void commitSession() {        SessionRepositoryFilter<S>.SessionRepositoryRequestWrapper.HttpSessionWrapper wrappedSession = this.getCurrentSession();        if (wrappedSession == null) {          if (this.isInvalidateClientSession()) {            SessionRepositoryFilter.this.httpSessionIdResolver.expireSession(this, this.response);          }        } else {          S session = wrappedSession.getSession();          this.clearRequestedSessionCache();          SessionRepositoryFilter.this.sessionRepository.save(session);          String sessionId = session.getId();          if (!this.isRequestedSessionIdValid() || !sessionId.equals(this.getRequestedSessionId())) {            SessionRepositoryFilter.this.httpSessionIdResolver.setSessionId(this, this.response, sessionId);          }        }        }

配置類:org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration

配置類:org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessionConfiguration

繼承SpringHttpSessionConfiguration

總結:

通過此次源碼閱讀,更加理解了接口是面對不同場景或變化時,一種智慧的抽象.

參考

https://docs.spring.io/spring-session/docs/current/reference/html5/