小编给大家分享一下spring-session如何实现,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!
一:spring-session介绍
1.简介
session一直都是我们做集群时需要解决的一个难题,过去我们可以从serlvet容器上解决,比如开源servlet容器-tomcat提供的tomcat-redis-session-manager、memcached-session-manager。
或者通过nginx之类的负载均衡做ip_hash,路由到特定的服务器上..
但是这两种办法都存在弊端。
spring-session是spring旗下的一个项目,把servlet容器实现的httpSession替换为spring-session,专注于解决 session管理问题。可简单快速且无缝的集成到我们的应用中。
支持功能
1)轻易把session存储到第三方存储容器,框架提供了redis、jvm的map、mongo、gemfire、hazelcast、jdbc等多种存储session的容器的方式。
2)同一个浏览器同一个网站,支持多个session问题。
3)RestfulAPI,不依赖于cookie。可通过header来传递jessionID
4)WebSocket和spring-session结合,同步生命周期管理。
集成方式
集成方式非常简单,直接看官网的samplesandguide。http://docs.spring.io/spring-session/docs/1.3.0.RELEASE/reference/html5/
主要分为以下几个集成步骤:
1)引入依赖jar包
2)注解方式或者xml方式配置特定存储容器的存储方式,如redis的xml配置方式
<context:annotation-config/> <beanclass="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/> <beanclass="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory"/>
3)xml方式配置 web.xml ,配置 springSessionFilter到 filter chain中
<filter> <filter-name>springSessionRepositoryFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSessionRepositoryFilter</filter-name> <url-pattern>public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerRequestFilter { private final SessionRepository<S> sessionRepository; private ServletContext servletContext; private MultiHttpSessionStrategy httpSessionStrategy = new CookieHttpSessionStrategy(); public SessionRepositoryFilter(SessionRepository<S> sessionRepository) { if (sessionRepository == null) { throw new IllegalArgumentException("sessionRepository cannot be null"); } this.sessionRepository = sessionRepository; } public void setHttpSessionStrategy(HttpSessionStrategy httpSessionStrategy) { if (httpSessionStrategy == null) { throw new IllegalArgumentException("httpSessionStrategy cannot be null"); } this.httpSessionStrategy = new MultiHttpSessionStrategyAdapter( httpSessionStrategy); } public void setHttpSessionStrategy(MultiHttpSessionStrategy httpSessionStrategy) { if (httpSessionStrategy == null) { throw new IllegalArgumentException("httpSessionStrategy cannot be null"); } this.httpSessionStrategy = httpSessionStrategy; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository); SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper( request, response, this.servletContext); SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper( wrappedRequest, response); HttpServletRequest strategyRequest = this.httpSessionStrategy .wrapRequest(wrappedRequest, wrappedResponse); HttpServletResponse strategyResponse = this.httpSessionStrategy .wrapResponse(wrappedRequest, wrappedResponse); try { filterChain.doFilter(strategyRequest, strategyResponse); } finally { wrappedRequest.commitSession(); } } public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; } private final class SessionRepositoryResponseWrapper extends OnCommittedResponseWrapper { private final SessionRepositoryRequestWrapper request; SessionRepositoryResponseWrapper(SessionRepositoryRequestWrapper request, HttpServletResponse response) { super(response); if (request == null) { throw new IllegalArgumentException("request cannot be null"); } this.request = request; } @Override protected void onResponseCommitted() { this.request.commitSession(); } } private final class SessionRepositoryRequestWrapper extends HttpServletRequestWrapper { private Boolean requestedSessionIdValid; private boolean requestedSessionInvalidated; private final HttpServletResponse response; private final ServletContext servletContext; private SessionRepositoryRequestWrapper(HttpServletRequest request, HttpServletResponse response, ServletContext servletContext) { super(request); this.response = response; this.servletContext = servletContext; } private void commitSession() { HttpSessionWrapper wrappedSession = getCurrentSession(); if (wrappedSession == null) { // session失效,删除cookie或者header if (isInvalidateClientSession()) { SessionRepositoryFilter.this.httpSessionStrategy .onInvalidateSession(this, this.response); } } else { S session = wrappedSession.getSession(); SessionRepositoryFilter.this.sessionRepository.save(session); if (!isRequestedSessionIdValid() || !session.getId().equals(getRequestedSessionId())) { // 把cookie或者header写回给浏览器保存 SessionRepositoryFilter.this.httpSessionStrategy.onNewSession(session, this, this.response); } } } @SuppressWarnings("unchecked") private HttpSessionWrapper getCurrentSession() { return (HttpSessionWrapper) getAttribute(CURRENT_SESSION_ATTR); } private void setCurrentSession(HttpSessionWrapper currentSession) { if (currentSession == null) { removeAttribute(CURRENT_SESSION_ATTR); } else { setAttribute(CURRENT_SESSION_ATTR, currentSession); } } @SuppressWarnings("unused") public String changeSessionId() { HttpSession session = getSession(false); if (session == null) { throw new IllegalStateException( "Cannot change session ID. There is no session associated with this request."); } // eagerly get session attributes in case implementation lazily loads them Map<String, Object> attrs = new HashMap<String, Object>(); Enumeration<String> iAttrNames = session.getAttributeNames(); while (iAttrNames.hasMoreElements()) { String attrName = iAttrNames.nextElement(); Object value = session.getAttribute(attrName); attrs.put(attrName, value); } SessionRepositoryFilter.this.sessionRepository.delete(session.getId()); HttpSessionWrapper original = getCurrentSession(); setCurrentSession(null); HttpSessionWrapper newSession = getSession(); original.setSession(newSession.getSession()); newSession.setMaxInactiveInterval(session.getMaxInactiveInterval()); for (Map.Entry<String, Object> attr : attrs.entrySet()) { String attrName = attr.getKey(); Object attrValue = attr.getValue(); newSession.setAttribute(attrName, attrValue); } return newSession.getId(); } // 判断session是否有效 @Override public boolean isRequestedSessionIdValid() { if (this.requestedSessionIdValid == null) { String sessionId = getRequestedSessionId(); S session = sessionId == null ? null : getSession(sessionId); return isRequestedSessionIdValid(session); } return this.requestedSessionIdValid; } private boolean isRequestedSessionIdValid(S session) { if (this.requestedSessionIdValid == null) { this.requestedSessionIdValid = session != null; } return this.requestedSessionIdValid; } private boolean isInvalidateClientSession() { return getCurrentSession() == null && this.requestedSessionInvalidated; } private S getSession(String sessionId) { // 从session存储容器中根据sessionID获取session S session = SessionRepositoryFilter.this.sessionRepository .getSession(sessionId); if (session == null) { return null; } // 设置sesison的最后访问时间,以防过期 session.setLastAccessedTime(System.currentTimeMillis()); return session; } @Override public HttpSessionWrapper getSession(boolean create) { //快速获取session,可以理解为一级缓存、二级缓存这种关系 HttpSessionWrapper currentSession = getCurrentSession(); if (currentSession != null) { return currentSession; } //从httpSessionStratge里面根据cookie或者header获取sessionID String requestedSessionId = getRequestedSessionId(); if (requestedSessionId != null && getAttribute(INVALID_SESSION_ID_ATTR) == null) { //从存储容器获取session以及设置当次初始化属性 S session = getSession(requestedSessionId); if (session != null) { this.requestedSessionIdValid = true; currentSession = new HttpSessionWrapper(session, getServletContext()); currentSession.setNew(false); setCurrentSession(currentSession); return currentSession; } else { if (SESSION_LOGGER.isDebugEnabled()) { SESSION_LOGGER.debug( "No session found by id: Caching result for getSession(false) for this HttpServletRequest."); } setAttribute(INVALID_SESSION_ID_ATTR, "true"); } } if (!create) { return null; } if (SESSION_LOGGER.isDebugEnabled()) { SESSION_LOGGER.debug( "A new session was created. To help you troubleshoot where the session was created we provided a StackTrace (this is not an error). You can prevent this from appearing by disabling DEBUG logging for " + SESSION_LOGGER_NAME, new RuntimeException( "For debugging purposes only (not an error)")); } // 如果该浏览器或者其他http访问者是初次访问服务器,则为他创建个新的session S session = SessionRepositoryFilter.this.sessionRepository.createSession(); session.setLastAccessedTime(System.currentTimeMillis()); currentSession = new HttpSessionWrapper(session, getServletContext()); setCurrentSession(currentSession); return currentSession; } @Override public ServletContext getServletContext() { if (this.servletContext != null) { return this.servletContext; } // Servlet 3.0+ return super.getServletContext(); } @Override public HttpSessionWrapper getSession() { return getSession(true); } @Override public String getRequestedSessionId() { return SessionRepositoryFilter.this.httpSessionStrategy .getRequestedSessionId(this); } private final class HttpSessionWrapper extends ExpiringSessionHttpSession<S> { HttpSessionWrapper(S session, ServletContext servletContext) { super(session, servletContext); } @Override public void invalidate() { super.invalidate(); SessionRepositoryRequestWrapper.this.requestedSessionInvalidated = true; setCurrentSession(null); SessionRepositoryFilter.this.sessionRepository.delete(getId()); } } }}
看完了这篇文章,相信你对“spring-session如何实现”有了一定的了解,如果想了解更多相关知识,欢迎关注编程网行业资讯频道,感谢各位的阅读!