浏览 3446 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-08-02
最后修改:2011-08-02
额。前面罗嗦一通是前提,我的一个程序中的解决方法,不必像开启tomcat的session复制或者像memcached session mamager这样对tomcat的配置文件进行修改,只需要代码实现即可。 想法如下: 用memcached 存储用户信息,将会话的sessionId作为key,放了一个map用来存储信息, 这样在会话中如果所粘合的tomcat down掉,nginx将此次会话转发给其他服务器时候,将存储在memcached中的信息复制回来即可。像下面这样: request--sessionFilter(会话转移filter)--powerFilter(权限验证filter)--action-- 首先我在登录的时候做了如下操作:初始化信息 SessionCacheService.initSessionCache(sessionId,map); 因为采取iphash策略,用户会话是粘合在同一服务器上的,那么当这台服务器down掉后的处理: 用request.getRequestedSessionId();获取上一会话的sessionId去memcached中找,找到后将信息复制到此会话中. /** * Created by IntelliJ IDEA. * User: bjslogin[at]gmail.com * Date: 11-8-2 * Time: 上午10:28 * 设置nginx为iphash,如果发生故障转移,即会将session信息转移至新的服务器 */ public class SessionFilter implements Filter { private Logger logger = Logger.getLogger(getClass()); public void init(FilterConfig filterConfig) throws ServletException { } public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)servletRequest; String url = request.getRequestURI(); for(String c : PowerFilter.noFilterPages){ if(url.indexOf(c) > 0){ filterChain.doFilter(servletRequest,servletResponse); return; } } String requestedSessionId = request.getRequestedSessionId(); HttpSession session = request.getSession(); if(requestedSessionId.equals(session.getId())){ filterChain.doFilter(servletRequest,servletResponse); return; } Map<String,Object> _map = SessionCacheService.getSessionCache(session.getId()); if(_map == null){ Map<String,Object> map = SessionCacheService.getSessionCache(requestedSessionId); if(map == null){ filterChain.doFilter(servletRequest,servletResponse); return; } logger.info("开始转移..."); SessionCacheService.initSessionCache(session.getId(),map); } filterChain.doFilter(servletRequest,servletResponse); } public void destroy() { } } 然后我的powerFilter 权限验证filter如下: /** * Created by IntelliJ IDEA. * User: bjslogin[at]gmail.com * Date: 11-8-1 * Time: 下午2:23 * 权限验证filter */ public class PowerFilter implements Filter { private Logger logger = Logger.getLogger(getClass()); private FilterConfig filterConfig; private ApplicationContext ctx = null; protected static final String sessionErrorPage = "/sessionError.jsp"; protected static final String noPermissionPage = "/noPermission.jsp"; protected static final String[] noFilterPages = {"login.action","logout.action"}; public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; } public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)servletRequest; String url = request.getRequestURI(); logger.info("【"+request.getRemoteHost()+"[at]"+new Date()+"】"+url); for(String c : noFilterPages){ if(url.indexOf(c) > 0){ filterChain.doFilter(servletRequest,servletResponse); return; } } HttpSession session = request.getSession(); Map<String,Object> map = SessionCacheService.getAndRefreshSessionCache(session.getId()); if(map == null){ HttpServletResponse response = (HttpServletResponse)servletResponse; response.sendRedirect(request.getContextPath() + sessionErrorPage); return; } LoginService loginService = (LoginService)getBean(LoginService.class); boolean flag = loginService.checkPrivate(request.getSession().getId(),StringUtils.substringAfter(url,request.getContextPath() + "/")); if(!flag){ HttpServletResponse response = (HttpServletResponse)servletResponse; response.sendRedirect(request.getContextPath() + noPermissionPage); return; } filterChain.doFilter(servletRequest,servletResponse); } public void destroy() { } public Object getBean(Class clazz) { if (ctx == null) { ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(filterConfig.getServletContext()); } return ctx.getBean(clazz); } } 看的出来我是用cache里面的信息来判断会话失效的,放弃使用HttpSession了,只用了它的ID,当然,这只是我的个人做法,要使用session存储信息的话,就是类似于将将memcached作为一个session信息的备份了,添加两个listener保证session和memcached同步即可,我的做法: /** * Created by IntelliJ IDEA. * User: bjslogin[at]gmail.com * Date: 11-8-1 * Time: 上午11:07 * session失效时同时干掉缓存 */ public class SessionCacheListener implements HttpSessionListener{ public void sessionCreated(HttpSessionEvent httpSessionEvent) { // do nothing // 登陆时才初始化sessionCache内容 } //session失效时同时移除缓存内容 public void sessionDestroyed(HttpSessionEvent httpSessionEvent) { HttpSession session = httpSessionEvent.getSession(); SessionCacheService.removeSessionCache(session.getId()); } } 这个是监听session属性变化的listener,保证当session内容变化时候能同步到cache中 /** * Created by IntelliJ IDEA. * User: bjslogin[at]gmail.com * Date: 11-8-1 * Time: 上午11:28 * 监听session属性变化,同步cache */ public class SessionCacheAttributeListener implements HttpSessionAttributeListener { public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) { HttpSession session = httpSessionBindingEvent.getSession(); String key = httpSessionBindingEvent.getName(); Object value = httpSessionBindingEvent.getValue(); SessionCacheService.putSessionCacheAttribute(session.getId(), key, value); } public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) { HttpSession session = httpSessionBindingEvent.getSession(); String key = httpSessionBindingEvent.getName(); SessionCacheService.removeSessionCacheAttribute(session.getId(), key); } public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) { attributeAdded(httpSessionBindingEvent); } } , 这样就能保证session与cache内容同步了,只需要在SessionFilter的SessionCacheService.initSessionCache(session.getId(),map);方法之前将cache中的内copy到session中即可,下一步的powerFIlter判断用户信息就不会出现问题。 在我本机nginx+3个tomcat测试中,将正在被访问的tomcat人为down掉,确实是能保证会话平滑转移的,我的nginx的集群配置方式: upstream localhost { ip_hash; server localhost:8060; server localhost:8070; server localhost:8080; } server { listen 8090; server_name localhost; location / { proxy_connect_timeout 3; proxy_send_timeout 30; proxy_read_timeout 30; proxy_pass http://localhost; } } } 不过据我所知,如果客户端禁用cookie的话,request.getRequestedSessionId()可能就有问题了,,不过。。不管啦! 这是我的一个解决方法,贴出来与大家分享。觉得这么做最大的好处就是和服务器无关,像session复制和memcached session manager这样都是依赖tomcat服务器。 毕业一年,还只是新手,这也是我在iteye的第一贴。。如果这么做有什么错误的话,请指正,我会虚心学习,请言论不要过激。。谢谢。 还有,看了精华贴 【晒晒大家年龄和近期愿望吧】 心中真是感慨万千,感觉天朝上学的时间真是太长了,刚毕业没多久,就觉得时间已经不够用。同时祝帖子里面的朋友愿望都能实现(话说最多的愿望是找个女朋友?)! 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-08-02
本地session还是有一定作用的吧。最起码可以倒过来把它看做是memcache-session在local的备份,节省每次远程调用memcache的开销。
|
|
返回顶楼 | |