自定义request以实现共享session的功能(从redis拿)

总体思想:

掉用的时候直接调用代理实例对象获取即可,用拦截器,或者直接把HttpServletRequestWrapper替换掉

package com.houbank.session.filter;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import java.util.HashMap;

import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletRequestWrapper;

import javax.servlet.http.HttpSession;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import sun.util.logging.resources.logging;

import lombok.extern.java.Log;

import lombok.extern.log4j.Log4j2;

import com.houbank.session.manager.RedisTemplateDelegate;

import com.houbank.session.manager.WebSession;

import com.houbank.session.manager.WebSessionManager;

类1

/**

 * 

 * <p>通过继承HttpServletRequestWrapper 来实现</p>

 * @author houzhanshan

 * @version $Id: RemoteSessionRequest.java, v 0.1 2017年5月26日 下午11:40:51 houzhanshan Exp $

 */

public class RemoteSessionRequest extends HttpServletRequestWrapper {

public RemoteSessionRequest(HttpServletRequest request) {

super(request);

}

//复写getSession方法,外界使用的方法,每次用到session的时候,拿到系统自带的session,建立自己的代理session

@Override

public HttpSession getSession() {

return RemoteSessionHandler.getInstance(super.getSession());

}

}

类2

动态代理session

@Log4j2

class RemoteSessionHandler implements InvocationHandler {

// 模拟远程Session服务器,Key表示SessionId,Value表示该Session的内容

private static Map<String, Map<String, Object>> map = new ConcurrentHashMap<String, Map<String, Object>>();

private static Logger log= LoggerFactory.getLogger(RedisTemplateDelegate.class);

private HttpSession session = null;

private RemoteSessionHandler(HttpSession httpSession) {

this.session = httpSession;

};

         //静态方法

     //获取实例代理实例,调用代理

public static HttpSession getInstance(HttpSession httpSession) {

       //获取代理处理器实例

InvocationHandler handler = new RemoteSessionHandler(httpSession);

//调用代理

return (HttpSession) Proxy.newProxyInstance(httpSession.getClass().getClassLoader(), httpSession.getClass().getInterfaces(), handler);

}

//切入方法点

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

if ("setAttribute".equals(method.getName())) {

String id = session.getId();

Map<String, Object> m = map.get(id);

if (m == null) {

m = new HashMap<String, Object>();

}

WebSession webSession=WebSessionManager.getInstance().getSession(id);

if(webSession==null){

webSession=WebSessionManager.getInstance().createSession(id);

}else{

webSession=WebSessionManager.getInstance().getSession(id);

}

webSession.setAttribute((String) args[0], args[1]);

log.info("[存入]key:" + args[0] + ",value:" + args[1]);

return null;

} else if ("getAttribute".equals(method.getName())) {

String id = session.getId();

WebSession webSession= WebSessionManager.getInstance().getSession(id);

if(webSession==null){

return null;

}

Object result = webSession.getAttribute((String) args[0]);

log.info("[取出]key:" + args[0] + ",value:" + result);

return result;

}

return method.invoke(session, args);

}

}

每次请求的时候重置里面的request,改变拿到request的具体对象,从而改变拿到的session,改变拿值的地方

都有这么一个链,加入过滤器链,不管在哪个顺序,总是在调用资源之前,此时的就都做了,也就在具体资源要用之前就被过滤了(替换成自定义)

@WebFilter("/*")

public class SessionFilter implements Filter {

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

//chain就是过滤器链,dofilter就是向下一个链执行

        chain.doFilter(new RemoteSessionRequest((HttpServletRequest) request), response);

        

    }

此时需要

HttpServletRequest  request1 =     (HttpServletRequest) request;

HttpSession session = request1.getSession();

代理HttpSession生成RemoteSessionRequest.java

用这个方法就弄好了session的拦截处理

过滤器:

chain.doFilter(request,response)

一般filter都是一个链,web.xml 里面配置了几个就有几个。一个一个的连在一起 

request -> filter1 -> filter2 ->filter3 -> .... -> request resource.

可以提前跳转后return null,也可

附件说明:

core.session.filter

core.session.manager

core.monitor  拦截器

RemoteSessionRequest.java  包装session

SessionFilter.java拦截把包装好的request放入代替原有的request(代替requset用过滤器)(实现redis的单点登录内存session共享),代替框架中的实现类用回调机制,

这样可以代替一切

core.session.filter   代换requset  通过WebSessionManager用自己的session

core.session.manager  代换的里面用的redis(具体换requset的点)

WebUtils.java  获取bean

WebSessionManager.java  管理session

WebSessionManager.java  session的具体构造

RedisTemplateDelegate.java 用的redis模板

WebSession.java

也就是存每个用户session,及每个用户session拥有的属性,这样模拟了sso

public void setAttribute(String name, Object value) {

this.attributes.put(name, value);k-v

storageSet(this.storageId, this.attributes);  sessionid-v   redis中存sessionid  和map对象(装初始k-y和后面增加的k-v)

}   存在内存中,存在redis中

一个用户一个WebSession对象(一个sessionid一个对象),即自定义session,每个session操作更新attributes,保存redis

获取session--->通过sessionid  获取 attributes然后组装成session对象WebSession 

后期修改通过sessionid,获取本session,之后调用session内部的操作attributes方法处理本session

相关推荐