memcache缓存共享session实现

1、session共享问题介绍html

    session主要用于服务端存储用户会话信息,cookie用于浏览器存储用户会话信息。单系统服务session都存在同一个web容器中,例如tomcat中,用户请求都只访问这个容器中的session信息,除非容器挂了,否者不存在session取不到的状况。随着业务的扩展,应用用户的增长,当个容器存放系统应用消耗服务的cup和内存会不断增长,致使应用性能降低。此时考虑用nginx集群作应用的负载均衡请求分发,假设用ngnix集群三个服务,分别用A、B、C表示。按照未作session共享,仍然使用Servlet中HttpSession情景,假设此时访问的是A服务,那么session将存储在A服务中,此处若是A服务宕机,ngnix会将用户的请求分发到B或者C服务,可是B和C服务中没有存A存放的Session信息,那么用户访问的数据将会丢失。为了解决session数据丢失,须要将session共享,主流作法是将session存储在nosql数据库中,例如memcache、redis等。也有不少人经过spring session 实现共享,原理大体同样,下面主要实现了memcache缓存session共享。java

2、核心代码:nginx

一、ShareSession.java web

package com.gccode.sso.session;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.gccode.sso.cache.BaseCache;
import com.gccode.sso.common.CookieUtils;

/**
 * Title: 缓存共享session实现类
 *
 */
public class ShareSession {
	
	/**
	 * 存到缓存中的共享session容器
	 */
	private Map<String,Object> sessionWrapper;
	
	/**
	 * session对象
	 */
	private static ShareSession session;
	
	/**
	 * 浏览器请求回话id
	 */
	private String sessionId;
	
	/**
	 * 缓存
	 */
    private BaseCache cache;
    
    /**
     * 构造函数初始化参数
     * @param request
     */
	public ShareSession(HttpServletRequest request){
		WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
		this.cache = (BaseCache) wac.getBean("cache");
		this.sessionId =  CookieUtils.getCookieId(request);
		this.sessionWrapper = new HashMap<String, Object>();
	}
	
	/**
	 * 获取session对象
	 * @param request
	 * @return
	 */
	public static synchronized ShareSession get(HttpServletRequest request){
		if(session == null){
			session = new ShareSession(request);
		}
		return session;
	}

	/**
	 * 设置session,带超时时间
	 * @param key
	 * @param value
	 * @param outTime
	 * @return sessionId
	 */
	public String setSession(String key,Object value,int outTime) {
		sessionWrapper.put(key, value);
		cache.put(sessionId,sessionWrapper,outTime);
		return sessionId;
	}
	
	/**
	 * 设置session
	 * @param key
	 * @param value
	 * @return
	 */
	public String setSession(String key,Object value) {
		sessionWrapper.put(key, value);
		cache.put(sessionId, sessionWrapper);
		return sessionId;
	}

	/**
	 * 设置session,不带超时时间
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public  Map<String, Object> getSession() {
		return (Map<String, Object>)cache.get(sessionId);
	}

	/**
	 * 删除session中的值
	 * @param key
	 */
	public void removeSession(String key) {
		Map<String,Object> session = getSession();
		session.remove(key);
		cache.put(sessionId,session);
	}

}

二、ShareSessionIntercept.javaredis

package com.gccode.sso.session;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.gccode.sso.cache.BaseCache;
import com.gccode.sso.common.CookieUtils;

/**
 * Title: 缓存共享session实现类
 *
 */
public class ShareSession {
	
	/**
	 * 存到缓存中的共享session容器
	 */
	private Map<String,Object> sessionWrapper;
	
	/**
	 * session对象
	 */
	private static ShareSession session;
	
	/**
	 * 浏览器请求回话id
	 */
	private String sessionId;
	
	/**
	 * 缓存
	 */
    private BaseCache cache;
    
    /**
     * 构造函数初始计划参数
     * @param request
     */
	public ShareSession(HttpServletRequest request){
		WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
		this.cache = (BaseCache) wac.getBean("cache");
		this.sessionId =  CookieUtils.getCookieId(request);
		this.sessionWrapper = new HashMap<String, Object>();
	}
	
	/**
	 * 获取session对象
	 * @param request
	 * @return
	 */
	public static synchronized ShareSession get(HttpServletRequest request){
		if(session == null){
			session = new ShareSession(request);
		}
		return session;
	}

	/**
	 * 设置session,带超时时间
	 * @param key
	 * @param value
	 * @param outTime
	 * @return sessionId
	 */
	public String setSession(String key,Object value,int outTime) {
		sessionWrapper.put(key, value);
		cache.put(sessionId,sessionWrapper,outTime);
		return sessionId;
	}
	
	/**
	 * 设置session
	 * @param key
	 * @param value
	 * @return
	 */
	public String setSession(String key,Object value) {
		sessionWrapper.put(key, value);
		cache.put(sessionId, sessionWrapper);
		return sessionId;
	}

	/**
	 * 设置session,不带超时时间
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public  Map<String, Object> getSession() {
		return (Map<String, Object>)cache.get(sessionId);
	}

	/**
	 * 删除session中的值
	 * @param key
	 */
	public void removeSession(String key) {
		Map<String,Object> session = getSession();
		session.remove(key);
		cache.put(sessionId,session);
	}

}

三、SSOUserFilter.javaspring

package com.gccode.sso.session;

import java.io.IOException;
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.apache.commons.lang3.StringUtils;
import org.springframework.cache.Cache;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.gccode.sso.common.Constant;
import com.gccode.sso.common.CookieUtils;


/**
 * Title: 用户请求过滤
 *
 */
public class SSOUserFilter implements Filter{

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse res,
			FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
		String sessionId = CookieUtils.getCookieId(request);
		WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(req.getServletContext());
		Cache cache = (Cache) wac.getBean("cache");
		if (StringUtils.isEmpty(sessionId) || null == cache.get(sessionId)) {
			request.getRequestDispatcher("/logout.html").forward(request,
					response);
		} else {
			@SuppressWarnings("unchecked")
			Map<String, Object> session = (Map<String, Object>) cache.get(
					sessionId).get();
			if (session.get(Constant.SESSION_USER_KEY) == null) {
				request.getRequestDispatcher("/logout.html").forward(request,
						response);
			} else {
				chain.doFilter(req, res);
			}
		}
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

}