最近项目设计集群,实现了一下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
(2)HttpServletRequestWrapper实现
/*** 创建时间:2016年1月22日 下午7:52:29* * @author andy* @version 2.2*/public class HttpServletRequestWrapper extendsjavax.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);}}@Overridepublic 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;}@Overridepublic 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);@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {//从COOKIE中获取sessionId,如果此次请求没有sessionId,重写为这次请求设置一个sessionIdString 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();@Autowiredprivate RedisTemplate
}
(5)Session的拦截配置,一般的我们只需要拦截我们定义的拦截请求拦截,而不需要所有的都需要拦截。在web.xml中配置SessionFilter。
<filter><filter-name>sessionFilterfilter-name><filter-class>org.andy.shop.session.SessionFilterfilter-class>filter><filter-mapping><filter-name>sessionFilterfilter-name>
附&#xff1a;设计到的工具类
1、StringUtil工具类
/*** String工具类* * &#64;author andy* &#64;date 2015-5-16 下午4:04:22* */
public class StringUtil {private StringUtil() {super();}/*** 出去null和""* &#64;param src* &#64;return*/public static String formatNull(String src) {return (src &#61;&#61; null || "null".equals(src)) ? "" : src;}/*** 判断字符串是否为空的正则表达式&#xff0c;空白字符对应的unicode编码*/private static final String EMPTY_REGEX &#61; "[\\s\\u00a0\\u2007\\u202f\\u0009-\\u000d\\u001c-\\u001f]&#43;";/*** 验证字符串是否为空* * &#64;param input* &#64;return*/public static boolean isEmpty(String input) {return input &#61;&#61; 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工具类
/*** 创建时间&#xff1a;2016年1月22日 下午8:33:56* * &#64;author andy* &#64;version 2.2*/public class COOKIEUtil {private static final String KEY &#61; "jkdflsffff()kldkjapfdY&#61;::$B&#43;DUOWAN";private HttpServletRequest request;private HttpServletResponse response;private static String domain &#61; "andy.com";public COOKIEUtil(HttpServletRequest request, HttpServletResponse response) {this.request &#61; request;this.response &#61; response;}/*** 保存COOKIE* &#64;param request* &#64;param response* &#64;param name COOKIE名称* &#64;param value COOKIE值* &#64;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 &#61; new COOKIE(name, value);//COOKIE.setDomain(domain);COOKIE.setMaxAge(seconds); COOKIE.setPath("/");response.setHeader("P3P","CP&#61;&#39;IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT&#39;");response.addCOOKIE(COOKIE);}/*** 过去COOKIE中保存的值* &#64;param name* &#64;return* &#64;throws UnsupportedEncodingException*/public String getCOOKIEValue(String name)throws UnsupportedEncodingException {COOKIE COOKIEs[] &#61; request.getCOOKIEs();if (COOKIEs !&#61; null) {for (int i &#61; 0; i
}
3、redis键key设置类RedisKeyUtil
/*** 创建时间&#xff1a;2015年9月22日 下午4:51:11* * &#64;author andy* &#64;version 2.2*/public class RedisKeyUtil {public static final String SESSION_DISTRIBUTED_SESSIONID &#61; "session:distributed:"; //分布式session sessionid -- sessionvaluepublic static final Integer SESSION_TIMEOUT &#61; 2; //session 失效时间2小时}
4、分布式session常量设置类GlobalConstant
/*** 创建时间&#xff1a;2016年1月23日 上午11:16:56* * 分布式session常量* * &#64;author andy* &#64;version 2.2*/public class GlobalConstant {public static final String USER_SESSION_KEY &#61; "user_session_key";//用户session信息public static final String JSESSIONID &#61; "YHMJSESSIONID"; //jsessionid
}
分布式session在redis执行结果&#xff1a;