一般我们在做服务器集群的时候,都会配置nginx反向代理服务器。但是问题来了,多个服务器之间的session怎么共享的呢?
我在这里用的是redis,实现思路:
1.自己定义一个sessionId生成策略,在session.setAttribute操作的时候,生成一个CSESSIONID并写回服务器;
2.定义filter拦截请求,扩展HttpServletRequest,代理session实现类,扩展setAttribute方法和getAttribute方法;
3.每次请求更新cookie的生命周期和redis中键的生命周期,我这里设置的是30分钟。
我的代码并不优雅,也没有进行扩展,下面贴出我的实现:
1.简单的redis实现:
实际开发请与spring整合并配置池
import redis.clients.jedis.Jedis; public class JedisProvider { private static Jedis jedis; public static Jedis getJedis() { jedis = new Jedis("127.0.0.1", 6379); return jedis; } // public static void main(String[] args) { // Jedis jedis = getJedis(); // jedis.set("name", "tanlei"); // } }
2.CookieUtil
</pre><p><pre name="code" class="java">import java.util.UUID; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class CookieUtil { public static String cacheCSessionId = null; public static Integer KEY_EXPIRE_TIME = 30 * 60; /** * 获取JessionId * * @param request * @return */ public static String getJsessionId(HttpServletRequest request) { Cookie[] cookies = request.getCookies(); // 2:从Cookie数据中遍历查找 并取CSESSIONID if (null != cookies && cookies.length > 0) { for (Cookie cookie : cookies) { if ("CSESSIONID".equals(cookie.getName())) { // 有 直接返回 return cookie.getValue(); } } } return null; }
<pre name="code" class="java">public static String addCookie(HttpServletRequest request, HttpServletResponse response, Integer KEY_EXPIRE_TIME) { String csessionId = getJsessionId(request); if(csessionId == null || "".equals(csessionId)) { csessionId = UUID.randomUUID().toString().replaceAll("-", ""); } Cookie cookie = new Cookie("CSESSIONID", csessionId); cookie.setPath("/"); cookie.setMaxAge(KEY_EXPIRE_TIME); response.addCookie(cookie); return csessionId; } }
3.sessionfilter
import java.io.IOException; 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.Set; import java.util.concurrent.ConcurrentHashMap; 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.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import com.tanlei.bean.User; import com.tanlei.jedis.provider.CookieUtil; import com.tanlei.jedis.provider.JedisProvider; import redis.clients.jedis.Jedis; public class SessionFilter implements Filter{ private Jedis jedis = JedisProvider.getJedis(); @Override public void destroy() { }
@Override public void doFilter(ServletRequest req, ServletResponse rep, FilterChain chain) throws IOException, ServletException { //当session不为空的时候,要刷新cookie存活周期和redis中键的存活日期 String csessionId = CookieUtil.getJsessionId((HttpServletRequest) req); if(csessionId != null && !"".equals(csessionId)) { jedis.expire(csessionId, CookieUtil.KEY_EXPIRE_TIME); CookieUtil.addCookie((HttpServletRequest) req, (HttpServletResponse)rep, CookieUtil.KEY_EXPIRE_TIME); } // HttpSession session = ((HttpServletRequest)req).getSession(); // if(session != null) { // String jSessionId = CookieUtil.getJessionId((HttpServletRequest)req); //从cookie中取出,并且更新cookie的生命周期为30分钟 // jedis.expire(jSessionId, 60 * 30); // } chain.doFilter(new RemoteSessionRequest((HttpServletRequest) req, (HttpServletResponse)rep), rep); CookieUtil.cacheCSessionId= null; } @Override public void init(FilterConfig arg0) throws ServletException { } }
class RemoteSessionRequest extends HttpServletRequestWrapper { private HttpServletRequest request; private HttpServletResponse response; public RemoteSessionRequest(HttpServletRequest request, HttpServletResponse response) { super(request); this.request = request; this.response = response; } @Override public HttpSession getSession() { return RemoteSessionHandler.getInstance(super.getSession(),request, response); } }
class RemoteSessionHandler implements InvocationHandler { private Jedis jedis = JedisProvider.getJedis(); private HttpSession session = null; private HttpServletRequest request = null; private HttpServletResponse response = null; private RemoteSessionHandler(HttpSession httpSession, HttpServletRequest request, HttpServletResponse response) { this.session = httpSession; this.request = request; this.response = response; }; 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 { if ("setAttribute".equals(method.getName())) { String csessionId = CookieUtil.getJsessionId(request); //放入cookie,csessionId if(csessionId == null || "".equals(csessionId)) { csessionId = CookieUtil.addCookie(request, response, CookieUtil.KEY_EXPIRE_TIME); CookieUtil.cacheCSessionId = csessionId; } <pre name="code" class="java"> } else if ("getAttribute".equals(method.getName())) { String csessionId = CookieUtil.getJsessionId(request); //从cookie中取出 if(csessionId == null || "".equals(csessionId)) { //从cacheCSessionId中取出,并判断 if(CookieUtil.cacheCSessionId == null || "".equals(CookieUtil.cacheCSessionId)) { return null; } else { csessionId = CookieUtil.cacheCSessionId; } } //根据csessionid去redis中取数据 Set<String> userIds = jedis.hkeys(csessionId); String userId = null; for(String id : userIds) { userId = id; } User user = null; if(userIds.size() > 0) { String userName = jedis.hget(csessionId, userId); user = new User(Integer.parseInt(userId), userName); } //封装对象并反回,清除数据 CookieUtil.cacheCSessionId = null; return user; }
} return method.invoke(session, args); } }
<filter> <filter-name>SessionFilter</filter-name> <filter-class> com.tanlei.filter.SessionFilter </filter-class> </filter> <filter-mapping> <filter-name>SessionFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>sessionSetServlet</servlet-name> <servlet-class>com.tanlei.controller.SessionSetServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>sessionSetServlet</servlet-name> <url-pattern>/sessionSetServlet</url-pattern> </servlet-mapping>
<welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list>
public class SessionSetServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("1111"); HttpSession session= request.getSession(); session.setAttribute("user", new User(2, "ergou")); System.out.println(request.getContextPath()); //response.sendRedirect(request.getContextPath() + "/index.jsp"); request.getRequestDispatcher("index.jsp").forward(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
commons-logging-1.1.3.jar
jedis-2.7.2.jar
测试redis使用的是:
redis64-3.0.501(基于windows)
9. User实体:
public class User { private Integer id; private String userName; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUserName() { return userName; } public User(Integer id, String userName) { super(); this.id = id; this.userName = userName; } public void setUserName(String userName) { this.userName = userName; } }