如何使用Spring+redis实现对session的分布式管理

在Spring中实现分布式 session管理

成都创新互联公司成立于2013年,我们提供高端网站建设公司成都网站制作成都网站设计、网站定制、营销型网站建设微信小程序开发、微信公众号开发、成都网站营销服务,提供专业营销思路、内容策划、视觉设计、程序开发来完成项目落地,为成都餐厅设计企业提供源源不断的流量和订单咨询。

本文主要是在Spring中实现分布式session,采用redis对session进行持久化管理,这样当应用部署的时候,不需要在Resin、Tomcat等容器里面进行分布式配置,方便加入新的节点服务器进行集群扩容,session不依赖各节点的服务器,可直接从redis获取。下面是功能的核心代码:

一、首先在web.xml里面配置

加入拦截器:


  
    distributedSessionFilter
    DistributedSessionFilter
    
      
      key
      xxxxxxxx
    
    
      
      cacheBean
      bean:redisPersistent//DistributedBaseInterFace,对应于此接口,进行session的持久化操作
    
    
      
      cookieName
      TESTSESSIONID
    
  
  
    distributedSessionFilter
    *.do
  
  

二、拦截器的实现,核心代码如下

主要有以下的几个类:

  1. DistributedSessionFilter,
  2. DistributedSessionManager,
  3. DistributedHttpSessionWrapper,
  4. DistributedHttpServletRequestWrapper

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 allAttribute = distributedSessionManager.getSession(actualSid, request.getSession()
          .getMaxInactiveInterval());
      distSession = new DistributedHttpSessionWrapper(actualSid, request.getSession(), allAttribute);
    } catch (Throwable e) {
      // 出错,删掉缓存数据
      log.error(e.getMessage(), e);
      Map allAttribute = new HashMap();
      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 getSession(String sid,int second) {
    String json = this.distributedBaseInterFace.get(sid,second);
    if (StringUtil.isNotBlank(json)) {
      return JsonUtil.unserializeMap(json);
    }
    return new HashMap(1);
  }

  //保存session
  public void saveSession(DistributedHttpSessionWrapper session) {
    Map 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 allAttribute;

  public DistributedHttpSessionWrapper(String sid, HttpSession session, Map 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 getAttributeNames() {
    Set set = allAttribute.keySet();
    Iterator iterator = set.iterator();
    return new MyEnumeration(iterator);
  }

  private class MyEnumeration implements Enumeration {
    Iterator iterator;

    public MyEnumeration(Iterator 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公司主要就是采用此方式。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持创新互联。


文章名称:如何使用Spring+redis实现对session的分布式管理
当前链接:http://ybzwz.com/article/johgod.html