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

来源:互联网 发布:51单片机时钟程序 编辑:程序博客网 时间:2024/05/17 19:21

在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 -->

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

主要有以下的几个类:
DistributedSessionFilter,
DistributedSessionManager,
DistributedHttpSessionWrapper,
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<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公司主要就是采用此方式。

0 0
原创粉丝点击