您好,登錄后才能下訂單哦!
在Spring中實現分布式 session管理
本文主要是在Spring中實現分布式session,采用redis對session進行持久化管理,這樣當應用部署的時候,不需要在Resin、Tomcat等容器里面進行分布式配置,方便加入新的節點服務器進行集群擴容,session不依賴各節點的服務器,可直接從redis獲取。下面是功能的核心代碼:
一、首先在web.xml里面配置
加入攔截器:
<!-- 分布式session start --> <filter> <filter-name>distributedSessionFilter</filter-name> <filter-class>DistributedSessionFilter</filter-class> <init-param> <!-- 必填,密鑰.2種方式,1對應為bean,格式為bean:key。2字符串,格式如:afffrfgv--> <param-name>key</param-name> <param-value>xxxxxxxx</param-value> </init-param> <init-param> <!-- 必填,redis對應的bean,格式為bean:xx--> <param-name>cacheBean</param-name> <param-value>bean:redisPersistent</param-value>//DistributedBaseInterFace,對應于此接口,進行session的持久化操作 </init-param> <init-param> <!-- 必填, --> <param-name>cookieName</param-name> <param-value>TESTSESSIONID</param-value> </init-param> </filter> <filter-mapping> <filter-name>distributedSessionFilter</filter-name> <url-pattern>*.do</url-pattern> </filter-mapping> <!-- 分布式session end -->
二、攔截器的實現,核心代碼如下
主要有以下的幾個類:
1、DistributedSessionFilter實現Filter:
import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; public class DistributedSessionFilter implements Filter { private static final Logger log = LoggerFactory.getLogger(DistributedSessionFilter.class); private String cookieName; //主要是對session進行管理的操作 private DistributedSessionManager distributedSessionManager; private String key; }
容器啟動時候的初始化方法:
@Override public void init(FilterConfig config) throws ServletException { WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(config .getServletContext()); String key = config.getInitParameter("key"); String cookieName = config.getInitParameter("cookieName"); String cacheBean = config.getInitParameter("cacheBean"); // 獲取bean的名稱,配置是"bean:" String redisBeanStr = cacheBean.substring(5); DistributedBaseInterFace distributedCache = (DistributedBaseInterFace) wac.getBean(redisBeanStr); // 獲取key,有2種配置方式,1對應為bean,格式為bean:key。2字符串 if (key.startsWith("bean:")) { this.key = (String) wac.getBean(key.substring(5)); } else { this.key = key; } this.cookieName = cookieName; this.distributedSessionManager = DistributedSessionManager.getInstance(distributedCache); //異常處理省略。。。 }
進行實際的請求攔截:
@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException { DistributedHttpServletRequestWrapper distReq = null; try { //請求處理 distReq = createDistributedRequest(servletRequest, servletResponse); filterChain.doFilter(distReq, servletResponse); } catch (Throwable e) { //省略。。。 } finally { if (distReq != null) { try { //處理完成request后,處理session(主要是保存session會話) dealSessionAfterRequest(distReq.getSession()); } catch (Throwable e2) { //省略。。。 } } } } //分布式請求 private DistributedHttpServletRequestWrapper createDistributedRequest(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; String userSid = CookieUtil.getCookie(cookieName, request); String actualSid = distributedSessionManager.getActualSid(userSid, request, key); if (StringUtil.isBlank(actualSid)) { if (StringUtil.isNotBlank(userSid)) { log.info("userSid[{}]驗證不通過", userSid); } // 寫cookie String[] userSidArr = distributedSessionManager.createUserSid(request, key); userSid = userSidArr[0]; CookieUtil.setCookie(cookieName, userSid, request, response); actualSid = userSidArr[1]; } actualSid = "sid:" + actualSid; DistributedHttpSessionWrapper distSession = null; try { Map<String, Object> allAttribute = distributedSessionManager.getSession(actualSid, request.getSession() .getMaxInactiveInterval()); distSession = new DistributedHttpSessionWrapper(actualSid, request.getSession(), allAttribute); } catch (Throwable e) { // 出錯,刪掉緩存數據 log.error(e.getMessage(), e); Map<String, Object> allAttribute = new HashMap<String, Object>(); distSession = new DistributedHttpSessionWrapper(actualSid, request.getSession(), allAttribute); distributedSessionManager.removeSession(distSession); } DistributedHttpServletRequestWrapper requestWrapper = new DistributedHttpServletRequestWrapper(request, distSession); return requestWrapper; } // request處理完時操作session private void dealSessionAfterRequest(DistributedHttpSessionWrapper session) { if (session == null) { return; } if (session.changed) { distributedSessionManager.saveSession(session); } else if (session.invalidated) { distributedSessionManager.removeSession(session); } else { distributedSessionManager.expire(session); } }
2、DistributedSessionManager,主要處理分布式session,核心代碼:
class DistributedSessionManager { protected static final Logger log = LoggerFactory.getLogger(DistributedSessionManager.class); private static DistributedSessionManager instance = null; //redis處理session的接口,自己根據情況實現 private DistributedBaseInterFace distributedBaseInterFace; private static byte[] lock = new byte[1]; private DistributedSessionManager(DistributedBaseInterFace distributedBaseInterFace) { this.distributedBaseInterFace = distributedBaseInterFace; } public static DistributedSessionManager getInstance(DistributedBaseInterFace redis) { if (instance == null) { synchronized (lock) { if (instance == null) { instance = new DistributedSessionManager(redis); } } } return instance; } //獲取session public Map<String, Object> getSession(String sid,int second) { String json = this.distributedBaseInterFace.get(sid,second); if (StringUtil.isNotBlank(json)) { return JsonUtil.unserializeMap(json); } return new HashMap<String, Object>(1); } //保存session public void saveSession(DistributedHttpSessionWrapper session) { Map<String, Object> map=session.allAttribute; if(MapUtil.isEmpty(map)){ return; } String json = JsonUtil.serializeMap(map); this.distributedBaseInterFace.set(session.getId(), json, session.getMaxInactiveInterval()); } //刪除session public void removeSession(DistributedHttpSessionWrapper session) { distributedBaseInterFace.del(session.getId()); } public void expire(DistributedHttpSessionWrapper session) { distributedBaseInterFace.expire(session.getId(), session.getMaxInactiveInterval()); } /** * 創建cookie的sid */ public String[] createUserSid(HttpServletRequest request, String key) { //... } public String getActualSid(String userSid, HttpServletRequest request, String key) { //... } }
3、DistributedHttpSessionWrapper 實現了 HttpSession,進行分布式session包裝,核心代碼:
public class DistributedHttpSessionWrapper implements HttpSession { private HttpSession orgiSession; private String sid; boolean changed = false; boolean invalidated = false; Map<String, Object> allAttribute; public DistributedHttpSessionWrapper(String sid, HttpSession session, Map<String, Object> allAttribute) { this.orgiSession = session; this.sid = sid; this.allAttribute = allAttribute; } @Override public String getId() { return this.sid; } @Override public void setAttribute(String name, Object value) { changed = true; allAttribute.put(name, value); } @Override public Object getAttribute(String name) { return allAttribute.get(name); } @Override public Enumeration<String> getAttributeNames() { Set<String> set = allAttribute.keySet(); Iterator<String> iterator = set.iterator(); return new MyEnumeration<String>(iterator); } private class MyEnumeration<T> implements Enumeration<T> { Iterator<T> iterator; public MyEnumeration(Iterator<T> iterator) { super(); this.iterator = iterator; } @Override public boolean hasMoreElements() { return iterator.hasNext(); } @Override public T nextElement() { return iterator.next(); } } @Override public void invalidate() { this.invalidated = true; } @Override public void removeAttribute(String name) { changed = true; allAttribute.remove(name); } @Override public long getCreationTime() { return orgiSession.getCreationTime(); } @Override public long getLastAccessedTime() { return orgiSession.getLastAccessedTime(); } @Override public int getMaxInactiveInterval() { return orgiSession.getMaxInactiveInterval(); } @Override public ServletContext getServletContext() { return orgiSession.getServletContext(); } @Override public Object getValue(String arg0) { return orgiSession.getValue(arg0); } @Override public String[] getValueNames() { return orgiSession.getValueNames(); } @Override public boolean isNew() { return orgiSession.isNew(); } @Override public void putValue(String arg0, Object arg1) { orgiSession.putValue(arg0, arg1); } @Override public void removeValue(String arg0) { orgiSession.removeValue(arg0); } @Override public void setMaxInactiveInterval(int arg0) { orgiSession.setMaxInactiveInterval(arg0); } @Override public HttpSessionContext getSessionContext() { return orgiSession.getSessionContext(); }
4、DistributedHttpServletRequestWrapper 實現了 HttpServletRequestWrapper,包裝處理過的session和原始request,核心代碼:
public class DistributedHttpServletRequestWrapper extends javax.servlet.http.HttpServletRequestWrapper { private HttpServletRequest orgiRequest; private DistributedHttpSessionWrapper session; public DistributedHttpServletRequestWrapper(HttpServletRequest request, DistributedHttpSessionWrapper session) { super(request); if (session == null){ //異常處理。。 } if (request == null){ //異常處理。。 } this.orgiRequest = request; this.session = session; } public DistributedHttpSessionWrapper getSession(boolean create) { orgiRequest.getSession(create); return session; } public DistributedHttpSessionWrapper getSession() { return session; } }
5、另外,定義DistributedBaseInterFace接口,用來處理session入redis進行持久化操作:
public interface DistributedBaseInterFace { /** * 根據key獲取緩存數據 * @param key * @param seconds */ public String get(String key,int seconds); /** * 更新緩存數據 * @param key * @param json * @param seconds */ public void set(String key, String json,int seconds); /** * 刪除緩存 * @param key */ public void del(String key); /** * 設置過期數據 * @param key * @param seconds */ public void expire(String key,int seconds);
注:本文只是在Spring中采用redis的方式對session進行管理,還有其他諸多的實現方式,比如在容器里面配置等,設計路由算法讓session依賴于集群中的各個節點服務器,,,,,,但redis這種方式在實際應用中還是比較廣泛的,LZ公司主要就是采用此方式。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。