Redis实现分布式session功能的共享

来源:互联网 发布:华为怎样隐藏软件 编辑:程序博客网 时间:2024/06/05 14:37
最近项目设计集群,实现了一下session的共享功能,其原理是将session保存到分布式缓存数据库中如:redis, memcache等,然后多个服务器tomcat每次请求都通过NoSql数据库查询,如果存在,则获取值;反之存放值。我是通过redis来实现session的共享,其主要有一下两种方法:1、通过tomcat服务器的拓展功能实现    这种方式比较简单,主要是通过继承session的ManagerBase类,实现重写session相关的方法,这种比较简单,    参考源码链接(http://download.csdn.net/detail/fengshizty/9417242)。2、通过filter拦截request请求实现    下面主要介绍这样实现方式:    (1)写HttpSessionWrapper实现HttpSession接口,实现里面session相关的方法。    (2)写HttpServletRequestWrapper继承javax.servlet.http.HttpServletRequestWrapper类,重写对于session  相关的方法。    (3)写SessionFilter拦截配置的请求url,过去cookie中    的sessionId,如果为空,对此次请求重写生成一个新的sessionId,在sessionId构造新的HttpServletRequestWrapper对象。    (4)写SessionService实现session到redis的保存和过去,其key为sessionId,value为session对于的Map。3、代码实现    (1)HttpSessionWrapper
/** * 创建时间:2016年1月21日 下午7:55:41 *  * @author andy * @version 2.2 */public class HttpSessionWrapper implements HttpSession {    private String sid = "";    private HttpSession session;    private HttpServletRequest request;    private HttpServletResponse response;    private Map<String, Object> map = null;    private SessionService sessionService = (SessionService) SpringContextHolder.getBean("sessionService");    public HttpSessionWrapper() {    }    public HttpSessionWrapper(HttpSession session) {        this.session = session;    }    public HttpSessionWrapper(String sid, HttpSession session) {        this(session);        this.sid = sid;    }    public HttpSessionWrapper(String sid, HttpSession session,            HttpServletRequest request, HttpServletResponse response) {        this(sid, session);        this.request = request;        this.response = response;    }    private Map<String, Object> getSessionMap() {        if (this.map == null) {            this.map = sessionService.getSession(this.sid);        }        return this.map;    }    @Override    public Object getAttribute(String name) {        if (this.getSessionMap() != null) {            Object value = this.getSessionMap().get(name);            return value;        }        return null;    }    @Override    public void setAttribute(String name, Object value) {        this.getSessionMap().put(name, value);        sessionService.saveSession(this.sid, this.getSessionMap());    }    @Override    public void invalidate() {        this.getSessionMap().clear();        sessionService.removeSession(this.sid);        CookieUtil.removeCookieValue(this.request,this.response, GlobalConstant.JSESSIONID);    }    @Override    public void removeAttribute(String name) {        this.getSessionMap().remove(name);        sessionService.saveSession(this.sid, this.getSessionMap());     }    @Override    public Object getValue(String name) {        return this.session.getValue(name);    }    @SuppressWarnings("unchecked")    @Override    public Enumeration getAttributeNames() {        return (new Enumerator(this.getSessionMap().keySet(), true));    }    @Override    public String[] getValueNames() {        return this.session.getValueNames();    }    @Override    public void putValue(String name, Object value) {        this.session.putValue(name, value);    }    @Override    public void removeValue(String name) {        this.session.removeValue(name);    }    @Override    public long getCreationTime() {        return this.session.getCreationTime();    }    @Override    public String getId() {        return this.sid;    }    @Override    public long getLastAccessedTime() {        return this.session.getLastAccessedTime();    }    @Override    public ServletContext getServletContext() {        return this.session.getServletContext();    }    @Override    public void setMaxInactiveInterval(int interval) {        this.session.setMaxInactiveInterval(interval);    }    @Override    public int getMaxInactiveInterval() {        return this.session.getMaxInactiveInterval();    }    @Override    public HttpSessionContext getSessionContext() {        return this.session.getSessionContext();    }    @Override    public boolean isNew() {        return this.session.isNew();    }}
(2)HttpServletRequestWrapper实现
/** * 创建时间:2016年1月22日 下午7:52:29 *  * @author andy * @version 2.2 */public class HttpServletRequestWrapper extends        javax.servlet.http.HttpServletRequestWrapper {    private HttpSession session;    private HttpServletRequest request;    private HttpServletResponse response;    private String sid = "";    public HttpServletRequestWrapper(HttpServletRequest request) {        super(request);    }    public HttpServletRequestWrapper(String sid, HttpServletRequest request) {        super(request);        this.sid = sid;    }    public HttpServletRequestWrapper(String sid, HttpServletRequest request,            HttpServletResponse response) {        super(request);        this.request = request;        this.response = response;        this.sid = sid;        if (this.session == null) {            this.session = new HttpSessionWrapper(sid, super.getSession(false),                    request, response);        }    }    @Override    public HttpSession getSession(boolean create) {        if (this.session == null) {            if (create) {                this.session = new HttpSessionWrapper(this.sid,                        super.getSession(create), this.request, this.response);                return this.session;            } else {                return null;            }        }        return this.session;    }    @Override    public HttpSession getSession() {        if (this.session == null) {            this.session = new HttpSessionWrapper(this.sid, super.getSession(),                    this.request, this.response);        }        return this.session;    }}
(3)SessionFilter拦截器的实现
public class SessionFilter extends OncePerRequestFilter implements Filter {    private static final Logger LOG = Logger.getLogger(SessionFilter.class);    @Override    protected void doFilterInternal(HttpServletRequest request,            HttpServletResponse response, FilterChain filterChain)            throws ServletException, IOException {        //从cookie中获取sessionId,如果此次请求没有sessionId,重写为这次请求设置一个sessionId        String sid = CookieUtil.getCookieValue(request, GlobalConstant.JSESSIONID);        if(StringUtils.isEmpty(sid) || sid.length() != 36){            sid = StringUtil.getUuid();            CookieUtil.setCookie(request, response, GlobalConstant.JSESSIONID, sid, 60 * 60);         }        //交给自定义的HttpServletRequestWrapper处理        filterChain.doFilter(new HttpServletRequestWrapper(sid, request, response), response);    }}
(4)SessionService实现session从redis的读写存储
public class SessionService {    private final static Logger LOG = Logger.getLogger(SessionService.class);    private JdkSerializationRedisSerializer jdkSerializer = new JdkSerializationRedisSerializer();    @Autowired    private RedisTemplate<Serializable, Serializable> redisTemplate;    @SuppressWarnings("unchecked")    public Map<String, Object> getSession(String sid) {        Map<String, Object> session = new HashMap<String, Object>();        try {            Object obj = redisTemplate.opsForValue()                    .get(RedisKeyUtil.SESSION_DISTRIBUTED_SESSIONID + sid);            if(obj != null){                obj = jdkSerializer.deserialize((byte[])obj);                session = (Map<String, Object>) obj;            }        } catch (Exception e) {            LOG.error("Redis获取session异常" + e.getMessage(), e.getCause());        }        return session;    }    public void saveSession(String sid, Map<String, Object> session) {        try {            redisTemplates.opsForValue()                    .set(RedisKeyUtil.SESSION_DISTRIBUTED_SESSIONID + sid,                            jdkSerializer.serialize(session), RedisKeyUtil.SESSION_TIMEOUT,                            TimeUnit.MINUTES);        } catch (Exception e) {            LOG.error("Redis保存session异常" + e.getMessage(), e.getCause());        }    }    public void removeSession(String sid) {        try {            redisTemplates.delete(                    RedisKeyUtil.SESSION_DISTRIBUTED_SESSIONID + sid);        } catch (Exception e) {            LOG.error("Redis删除session异常" + e.getMessage(), e.getCause());        }    }}
(5)Session的拦截配置,一般的我们只需要拦截我们定义的拦截请求拦截,而不需要所有的都需要拦截。在web.xml中配置SessionFilter。
<filter>        <filter-name>sessionFilter</filter-name>        <filter-class>org.andy.shop.session.SessionFilter</filter-class>    </filter>    <filter-mapping>        <filter-name>sessionFilter</filter-name>        <url-pattern>*.do</url-pattern>    </filter-mapping>

附:设计到的工具类

1、StringUtil工具类

/** * String工具类 *  * @author andy * @date 2015-5-16 下午4:04:22 *  */public class StringUtil {    private StringUtil() {        super();    }    /**     * 出去null和""     * @param src     * @return     */    public static String formatNull(String src) {        return (src == null || "null".equals(src)) ? "" : src;    }    /**     * 判断字符串是否为空的正则表达式,空白字符对应的unicode编码     */    private static final String EMPTY_REGEX = "[\\s\\u00a0\\u2007\\u202f\\u0009-\\u000d\\u001c-\\u001f]+";    /**     * 验证字符串是否为空     *      * @param input     * @return     */    public static boolean isEmpty(String input) {        return input == null || input.equals("") || input.matches(EMPTY_REGEX);    }    public static boolean isNotEmpty(String input){        return !isEmpty(input);    }    public static String getUuid() {        return UUID.randomUUID().toString();    }}

2、Cookie管理CookieUtil工具类

/** * 创建时间:2016年1月22日 下午8:33:56 *  * @author andy * @version 2.2 */public class CookieUtil {    private static final String KEY = "jkdflsffff()kldkjapfdY=::$B+DUOWAN";    private HttpServletRequest request;    private HttpServletResponse response;    private static String domain = "andy.com";    public CookieUtil(HttpServletRequest request, HttpServletResponse response) {        this.request = request;        this.response = response;    }    /**     * 保存cookie     * @param request     * @param response     * @param name cookie名称     * @param value cookie值     * @param seconds 过期时间(单位秒) -1代表关闭浏览器时cookie即过期     */    public static void setCookie(HttpServletRequest request,            HttpServletResponse response, String name, String value, int seconds) {        if (StringUtils.isEmpty(name) || StringUtils.isEmpty(value))            return;        Cookie cookie = new Cookie(name, value);        //cookie.setDomain(domain);        cookie.setMaxAge(seconds);         cookie.setPath("/");        response.setHeader("P3P",                "CP='IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT'");        response.addCookie(cookie);    }    /**     * 过去cookie中保存的值     * @param name     * @return     * @throws UnsupportedEncodingException     */    public String getCookieValue(String name)            throws UnsupportedEncodingException {        Cookie cookies[] = request.getCookies();        if (cookies != null) {            for (int i = 0; i < cookies.length; i++) {                if (name.equalsIgnoreCase(cookies[i].getName())) {                    return cookies[i].getValue();                }            }        }        return "";    }    /**     * 设置加密的cookie     * @param name cookie名称     * @param value cookie值     * @param seconds 过期时间 -1代表关闭浏览器时cookie即过期     */    public void setCheckCodeCookie(String name, String value, int seconds) {        if (StringUtils.isEmpty(name) || StringUtils.isEmpty(value)) {            return;        }        String md5Value = MD5Utils.getMD5(KEY + value);        Cookie cookie = new Cookie(name, md5Value);        //cookie.setDomain(domain);        cookie.setMaxAge(seconds);        cookie.setPath("/");        response.addCookie(cookie);    }    /**     * 校验加密的cookie     * @param name     * @param value     * @return     */    public boolean checkCodeCookie(String name, String value) {        if (StringUtils.isEmpty(name) || StringUtils.isEmpty(value)) {            return false;        }        boolean result = false;        String cookieValue = getCookieValue(request, name);        if (MD5Utils.getMD5(KEY + value).equalsIgnoreCase(                cookieValue)) {            result = true;        }        return result;    }    /**     * 获取cookie值     * @param request     * @param name     * @return     */    public static String getCookieValue(HttpServletRequest request, String name) {        try {            Cookie cookies[] = request.getCookies();            if (cookies != null) {                for (int i = 0; i < cookies.length; i++) {                    if (name.equalsIgnoreCase(cookies[i].getName())) {                        return cookies[i].getValue();                    }                }            }        } catch (Exception e) {        }        return "";    }    /**     * 移除客户端的cookie     * @param request     * @param response     * @param name     */    public static void removeCookieValue(HttpServletRequest request,            HttpServletResponse response, String name) {        try {            Cookie cookies[] = request.getCookies();            if (cookies != null && cookies.length > 0) {                for (Cookie cookie : cookies) {                    if (name.equalsIgnoreCase(cookie.getName())) {                        cookie = new Cookie(name, null);                        cookie.setMaxAge(0);                        cookie.setPath("/");                        //cookie.setDomain(domain);                        response.addCookie(cookie);                        break;                    }                }            }        } catch (Exception e) {            e.printStackTrace();        }    }}

3、redis键key设置类RedisKeyUtil

/** * 创建时间:2015年9月22日 下午4:51:11 *  * @author andy * @version 2.2 */public class RedisKeyUtil {    public static final String SESSION_DISTRIBUTED_SESSIONID = "session:distributed:"; //分布式session sessionid -- sessionvalue    public static final Integer SESSION_TIMEOUT = 2; //session 失效时间2小时}

4、分布式session常量设置类GlobalConstant

/** * 创建时间:2016年1月23日 上午11:16:56 *  * 分布式session常量 *  * @author andy * @version 2.2 */public class GlobalConstant {    public static final String USER_SESSION_KEY = "user_session_key";//用户session信息    public static final String JSESSIONID = "YHMJSESSIONID"; //jsessionid}

分布式session在redis执行结果:
redis中session保存结果

0 0