Implement distributed session management in Spring
This article mainly implements distributed session in Spring, and uses redis to persist the session. In this way, when the application is deployed, there is no need to configure distributed in containers such as Resin and Tomcat, which is convenient for adding new node servers for cluster expansion. The session does not depend on servers of each node and can be obtained directly from redis. Here is the core code of the function:
1. First configure it in web.xml
Add to interceptor:
<!-- Distributed session start --> <filter> <filter-name>distributedSessionFilter</filter-name> <filter-class>DistributedSessionFilter</filter-class> <init-param> <!-- Required, key. 2 ways, 1 corresponds to bean, format is bean:key. 2 strings, formats such as: affffrfgv--> <param-name>key</param-name> <param-value>xxxxxxxx</param-value> </init-param> <init-param> <!-- Required, the bean corresponding to redis is bean:xx--> <param-name>cacheBean</param-name> <param-value>bean:redisPersistent</param-value>//DistributedBaseInterFace, corresponding to this interface, perform session persistence operation</init-param> <init-param> <!-- Required, --> <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> <!-- Distributed session end -->
2. The implementation of the interceptor, the core code is as follows
There are mainly the following categories:
1. DistributedSessionFilter implements 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; //It is mainly an operation to manage session private DistributedSessionManager distributedSessionManager; private String key;}Initialization method when container starts:
@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"); // Get the name of the bean, the configuration is "bean:" String redisBeanStr = cacheBean.substring(5); DistributedBaseInterFace distributedCache = (DistributedBaseInterFace) wac.getBean(redisBeanStr); // Get the key, there are 2 configuration methods, 1 corresponds to bean, and the format is bean:key. 2 string if (key.startsWith("bean:")) { this.key = (String) wac.getBean(key.substring(5)); } else { this.key = key; } this.cookieName = cookieName; this.distributedSessionManager = DistributedSessionManager.getInstance(distributedCache); //Exception handling is omitted. . . }Perform actual request interception:
@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException { DistributedHttpServletRequestWrapper distReq = null; try { //Request processing distReq = createDistributedRequest(servletRequest, servletResponse); filterChain.doFilter(distReq, servletResponse); } catch (Throwable e) { //Omitted. . . } finally { if (distReq != null) { try { //After processing the request, process the session (mainly saving the session session) dealSessionAfterRequest(distReq.getSession()); } catch (Throwable e2) { //Omitted. . . } } } } } //Distributed Request 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[{}] verification fails", userSid); } // Write 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) { // An error occurred, delete the cached data 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; } // Operation 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, mainly deals with distributed sessions, core code:
class DistributedSessionManager { protected static final Logger log = LoggerFactory.getLogger(DistributedSessionManager.class); private static DistributedSessionManager instance = null; //Redis handles session interface and implements 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; } //Get 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); } //Save 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()); } //Delete session public void removeSession(DistributedHttpSessionWrapper session) { distributedBaseInterFace.del(session.getId()); } public void expire(DistributedHttpSessionWrapper session) { distributedBaseInterFace.expire(session.getId(), session.getMaxInactiveInterval()); } /** * Create sid of the cookie */ public String[] createUserSid(HttpServletRequest request, String key) { //... } public String getActualSid(String userSid, HttpServletRequest request, String key) { //... }}3. DistributedHttpSessionWrapper implements HttpSession and performs distributed session packaging, core code:
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 implements HttpServletRequestWrapper, wraps the processed session and original request, core code:
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){ //Exception handling. . } if (request == null){ //Exception handling. . } this.orgiRequest = request; this.session = session; } public DistributedHttpSessionWrapper getSession(boolean create) { orgiRequest.getSession(create); return session; } public DistributedHttpSessionWrapper getSession() { return session; }}5. In addition, define the DistributedBaseInterFace interface to handle session into redis for persistence operations:
public interface DistributedBaseInterFace { /** * Get cached data based on key* @param key * @param seconds */ public String get(String key,int seconds); /** * Update cached data* @param key * @param json * @param seconds */ public void set(String key, String json,int seconds); /** * Delete cache* @param key */ public void del(String key); /** * Set expired data* @param key * @param seconds */ public void expire(String key,int seconds);Note: This article only uses the redis method to manage sessions in Spring, and there are many other implementation methods, such as configuration in containers, etc., and designs a routing algorithm to make sessions rely on various node servers in the cluster,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.