java集群中session共享有多种方案,比如可以使用tomcat的session复制的功能来实现集群session共享,但这样做的缺点也很明显,每台服务器上都需要存相同的session,性能随着服务器增加急剧下降,而且容易引起广播风暴。
最近学习了使用Memcached缓存服务器实现session集群共享,下面是学习笔记:
在开发阶段可以使用原生的本地session,在项目上线时再全部切换成远程session。
为了完成这个功能,可以先定义一个SessionProvider接口,项目中有关session的操作都通过调用这个接口的方法来实现。当在开发阶段时,使用实现SessionProvider接口的HttpSessionProvider类实现项目中有关session的操作,当项目上线时,把spring中配置的HttpSessionProvider换成使用Memcached api的CacheSessionProvider类,这样项目中注入的SessionProvider就是CacheSessionProvider了。
①首先是session供应接口:
public interface SessionProvider {
//往Session设置值
public void setAttribute(HttpServletRequest request,HttpServletResponse response, String name,Serializable value);
//从Session中取值
public Serializable getAttribute(HttpServletRequest request,HttpServletResponse response,String name);
//退出登陆
public void logout(HttpServletRequest request,HttpServletResponse response);
//获取SessionID
public String getSessionId(HttpServletRequest request,HttpServletResponse response);
}
②本地session实现类:
其中,request.getSession()方法默认参数为true,意思就是如果cookie中有JsessionId就去request中找,找到则使用,如果找不到就新建一个session。
因此request.getSession(false);的意思就是只找老的session,如果此JessionId没有对应的session,也不创建新的,返回null值。
public class HttpSessionProvider implements SessionProvider{
@Override
public void setAttribute(HttpServletRequest request,HttpServletResponse response, String name,
Serializable value) {
HttpSession session = request.getSession();
session.setAttribute(name, value);
}
@Override
public Serializable getAttribute(HttpServletRequest request,HttpServletResponse response, String name) {
HttpSession session = request.getSession(false);
if(session != null){
return (Serializable) session.getAttribute(name);
}
return null;
}
@Override
public void logout(HttpServletRequest request,HttpServletResponse response) {
HttpSession session = request.getSession(false);
if(session != null){
session.invalidate();
}
//Cookie JSESSIONID
}
@Override
public String getSessionId(HttpServletRequest request,HttpServletResponse response) {
return request.getSession().getId();
}
}
在Spring的配置文件里配置:
③存放在Memcached缓存服务器中的session功能实现类:
public class CacheSessionProvider implements SessionProvider{
@Autowired
private MemCachedClient memCachedClient;
private int expiry = 30;//分钟,这里有个参数可以在spring配置文件里进行缓存时间修改
private static final String JSESSIONID = "JSESSIONID";
//放值
@Override
public void setAttribute(HttpServletRequest request,HttpServletResponse response, String name,
Serializable value) {
Map session = new HashMap();
session.put(name, value);
//保存远程了
//这种自定义map代替session的方式不会自动生成jsessionid,所以需要调用下面的getSessionId方法
memCachedClient.set(getSessionId(request,response), session, expiry*60);
}
//取值
@SuppressWarnings("unchecked")
@Override
public Serializable getAttribute(HttpServletRequest request,HttpServletResponse response, String name) {
Map session = (Map) memCachedClient.get(getSessionId(request,response));
if(null != session){
return session.get(name);
}
return null;
}
@Override
public void logout(HttpServletRequest request,HttpServletResponse response) {
// TODO Auto-generated method stub
if(memCachedClient.keyExists(getSessionId(request, response))){
memCachedClient.delete(getSessionId(request, response));
}
}
@Override
public String getSessionId(HttpServletRequest request,HttpServletResponse response) {
//所有的Cookie
Cookie[] cookies = request.getCookies();
if(null != cookies && cookies.length > 0){
for(Cookie c : cookies){
if(JSESSIONID.equals(c.getName())){
return c.getValue();
}
}
}
//生成一个
String sessionId = UUID.randomUUID().toString().replaceAll("-", "");
Cookie cookie = new Cookie(JSESSIONID,sessionId);
cookie.setMaxAge(-1);
cookie.setPath("/");
response.addCookie(cookie);
return sessionId;
}
public void setExpiry(int expiry) {
this.expiry = expiry;
}
}
然后
在Spring的配置文件里更改配置: