不同服务器之间的HttpSession共享
场景:当服务部署在多台服务器中时,为了共享用户请求的session,因而在这里做一个多台服务器共享HttpSession的功能。
实现过程介绍:通过实现Filter过滤器,每次请求过来时,再通过动态代理的方式获取到当前HttpSession进行InvocationHandler的invoke方法反向代理HttpSession,当HttpSession接口的相关方法执行时将对应的sessionId存储到缓存Redis中,其中Redis的相关bean的获取是通过上下文对象中获取。
具体的代码
//当前的SessionFilter 配置到spring中作为bean,作为session过滤器。
public class SessionFilter extends OncePerRequestFilter implements Filter {
@Override
public void destroy() {
}
@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse rep, FilterChain filterChain) throws ServletException, IOException {
filterChain.doFilter(new RemoteSessionRequest((HttpServletRequest) req, (HttpServletResponse) rep), rep);
}
}
//该类通过继承HttpServletRequestWrapper ,创建该类时将request传给父类,父类执行getSession方法
class RemoteSessionRequest extends HttpServletRequestWrapper {
private HttpServletRequest request;
private HttpServletResponse response;
public RemoteSessionRequest(HttpServletRequest request, HttpServletResponse response) {
//创建该类时将request传给父类,父类执行getSession方法
super(request);
this.request = request;
this.response = response;
}
@Override
public HttpSession getSession() {
return RemoteSessionHandler.getInstance(super.getSession(), request, response);
}
}
class RemoteSessionHandler implements InvocationHandler {
private HttpSession session = null;
private HttpServletRequest request = null;
private HttpServletResponse response = null;
//通过上下文对象加载已初始化过的redisClientTemplate这个bean对象
private RedisClientTemplate redisClientTemplate = (RedisClientTemplate) SpringContextHolder.getBean("redisClientTemplate");
private RemoteSessionHandler(HttpSession httpSession, HttpServletRequest request, HttpServletResponse response) {
this.session = httpSession;
this.request = request;
this.response = response;
};
//动态的加载httpSession,在代理的过程中invoke方法处理相关的httpSession 方法调用
public static HttpSession getInstance(HttpSession httpSession, HttpServletRequest request, HttpServletResponse response) {
InvocationHandler handler = new RemoteSessionHandler(httpSession, request, response);
return (HttpSession) Proxy.newProxyInstance(httpSession.getClass().getClassLoader(), httpSession.getClass().getInterfaces(), handler);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//逻辑处理, 代理 当HttpSession接口中的setAttribute方法,getAttribute方法,removeAttribute方法在生命周期中执行时,将对用的sessionId放入到Redis中
if ("setAttribute".equals(method.getName())) {
String csessionId = CookieUtil.getJsessionId(request); // 放入cookie,csessionId
if (csessionId == null) {
csessionId = CookieUtil.addCookie(request, response, SystemConstant.KEY_EXPIRE_TIME);
}
if (csessionId != null && !"".equals(csessionId)) {
redisClientTemplate.hset((SystemConstant.redis_u + csessionId).getBytes(), String.valueOf(args[0]).getBytes(), SerializeUtil.serialize(args[1]));
redisClientTemplate.expire((SystemConstant.redis_u + csessionId).getBytes(), SystemConstant.KEY_EXPIRE_TIME);
}
} else if ("getAttribute".equals(method.getName())) {
String csessionId = CookieUtil.getJsessionId(request); // 从cookie中取出
if (!StringUtil.isEmpty(csessionId)) {
// 根据csessionid去redis中取数据
if (redisClientTemplate.hexists((SystemConstant.redis_u + csessionId).getBytes(), String.valueOf(args[0]).getBytes())) {
byte[] byt = redisClientTemplate.hget((SystemConstant.redis_u + csessionId).getBytes(), String.valueOf(args[0]).getBytes());
return SerializeUtil.unserialize(byt);
}
}
} else if ("removeAttribute".equals(method.getName())) {
String csessionId = CookieUtil.getJsessionId(request); // 从cookie中取出
if (!StringUtil.isEmpty(csessionId)) {
// 根据csessionid去redis中取数据
if (redisClientTemplate.hexists((SystemConstant.redis_u + csessionId).getBytes(), String.valueOf(args[0]).getBytes())) {
redisClientTemplate.hdel((SystemConstant.redis_u + csessionId).getBytes(), String.valueOf(args[0]).getBytes());
}
}
}
return method.invoke(session, args);
}
}
针对于session不同服务器间的共享场景下是可以使用这种方式进行共享处理,其中的动态代理httpSession接口,过滤器的使用,上下文中加载相关bean等都可以作为借鉴。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/80407.html