动态代理实现不同服务器之间的session共享

不同服务器之间的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等都可以作为借鉴。

你可能感兴趣的:(java中动态代理,session共享,spring,session,servlet,redis,java)