├── README.md ├── servlet3.x-webapp ├── src │ └── main │ │ ├── webapp │ │ ├── js │ │ │ └── welcome.js │ │ ├── index.jsp │ │ └── WEB-INF │ │ │ ├── weblogic.xml │ │ │ ├── views │ │ │ └── greeting.jsp │ │ │ └── web.xml │ │ └── java │ │ └── com │ │ └── github │ │ └── loafer │ │ └── servlet │ │ └── HelloServlet.java └── pom.xml ├── servlet2.x-webapp ├── src │ └── main │ │ └── webapp │ │ ├── index.jsp │ │ └── WEB-INF │ │ ├── views │ │ └── greeting.jsp │ │ └── web.xml └── pom.xml ├── 10.5-servlet3.x-directory-structure ├── src │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ └── resources │ │ │ ├── css │ │ │ └── test.css │ │ │ ├── js │ │ │ └── hello.js │ │ │ ├── views │ │ │ └── greeting.jsp │ │ │ └── index.jsp │ │ └── java │ │ └── com │ │ └── github │ │ └── loafer │ │ └── servlet │ │ └── GreetingServlet.java └── pom.xml ├── servlet3.x-servletContainerInitializer ├── src │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ └── services │ │ │ └── javax.servlet.ServletContainerInitializer.bak │ │ └── java │ │ └── com │ │ └── github │ │ └── loafer │ │ └── servlet │ │ ├── WebApplicationInitializer.java │ │ └── CustomServletContextListener.java └── pom.xml ├── .gitignore ├── servlet3.x-session ├── src │ └── main │ │ └── java │ │ └── com │ │ └── github │ │ └── loafer │ │ ├── session │ │ ├── LifeCycle.java │ │ ├── SessionIdManager.java │ │ ├── SessionStore.java │ │ ├── SessionManager.java │ │ ├── metadata │ │ │ └── SessionMetaData.java │ │ └── support │ │ │ ├── RedisHttpSession.java │ │ │ ├── DefaultSessionIdManager.java │ │ │ ├── SessionManagerImpl.java │ │ │ ├── RedisSessionStore.java │ │ │ └── AbstractDistributedHttpSession.java │ │ ├── servlet │ │ └── GreetingServlet.java │ │ ├── util │ │ └── SerializationUtils.java │ │ ├── helper │ │ └── CookieHelper.java │ │ └── filter │ │ └── DistributableSessionFilter.java └── pom.xml ├── webapp ├── src │ └── main │ │ └── webapp │ │ └── WEB-INF │ │ └── web.xml └── pom.xml ├── simple-distributed-sessions-manager ├── src │ └── main │ │ └── java │ │ └── com │ │ └── github │ │ └── loafer │ │ ├── distributed │ │ └── httpsession │ │ │ ├── LifeCycle.java │ │ │ ├── SessionIDManager.java │ │ │ ├── SessionManager.java │ │ │ ├── SessionStorage.java │ │ │ ├── manager │ │ │ ├── task │ │ │ │ ├── ClearInvalidSessionScheduledTask.java │ │ │ │ └── ClearInvalidSessionTask.java │ │ │ ├── NoStickySessionManager.java │ │ │ ├── StickySessionManager.java │ │ │ ├── DefaultSessionIDManager.java │ │ │ └── AbstractSessionManager.java │ │ │ ├── metadata │ │ │ └── SessionMetaData.java │ │ │ ├── util │ │ │ └── SerializationUtils.java │ │ │ ├── helper │ │ │ └── CookieHelper.java │ │ │ ├── session │ │ │ ├── NoStickyHttpSession.java │ │ │ ├── StickyHttpSession.java │ │ │ └── DistributedHttpSession.java │ │ │ ├── filter │ │ │ └── DistributableSessionFilter.java │ │ │ └── storage │ │ │ └── RedisSessionStorage.java │ │ └── greeting │ │ └── GreetingServlet.java └── pom.xml └── servlet2.x-session ├── src └── main │ └── java │ └── com │ └── github │ └── loafer │ ├── listener │ └── HttpSessionLifecycle.java │ ├── servlet │ └── GreetingServlet.java │ └── bean │ └── User.java └── pom.xml /README.md: -------------------------------------------------------------------------------- 1 | # servlet3-tutorials 2 | -------------------------------------------------------------------------------- /servlet3.x-webapp/src/main/webapp/js/welcome.js: -------------------------------------------------------------------------------- 1 | function sayHello(){ 2 | alert('Hello Servlet 3.0'); 3 | } -------------------------------------------------------------------------------- /servlet2.x-webapp/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Hello World!

4 | 5 | 6 | -------------------------------------------------------------------------------- /10.5-servlet3.x-directory-structure/src/main/resources/META-INF/resources/css/test.css: -------------------------------------------------------------------------------- 1 | body{ 2 | background-color: #c0c0c0; 3 | } -------------------------------------------------------------------------------- /10.5-servlet3.x-directory-structure/src/main/resources/META-INF/resources/js/hello.js: -------------------------------------------------------------------------------- 1 | function sayHello(){ 2 | alert('Hello World!'); 3 | } -------------------------------------------------------------------------------- /servlet3.x-servletContainerInitializer/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer.bak: -------------------------------------------------------------------------------- 1 | com.github.loafer.servlet.WebApplicationInitializer -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | *.ipr 3 | *.iws 4 | .idea/ 5 | target/ 6 | pom.xml.tag 7 | pom.xml.releaseBackup 8 | pom.xml.versionsBackup 9 | pom.xml.next 10 | release.properties 11 | -------------------------------------------------------------------------------- /servlet3.x-session/src/main/java/com/github/loafer/session/LifeCycle.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.session; 2 | 3 | /** 4 | * @author zhaojh 5 | */ 6 | public interface LifeCycle { 7 | void start(); 8 | void stop(); 9 | } 10 | -------------------------------------------------------------------------------- /webapp/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | Archetype Created Web Application 7 | 8 | -------------------------------------------------------------------------------- /simple-distributed-sessions-manager/src/main/java/com/github/loafer/distributed/httpsession/LifeCycle.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.distributed.httpsession; 2 | 3 | /** 4 | * @author zhaojh 5 | */ 6 | public interface LifeCycle { 7 | void start(); 8 | void stop(); 9 | } 10 | -------------------------------------------------------------------------------- /servlet3.x-session/src/main/java/com/github/loafer/session/SessionIdManager.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.session; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | 5 | /** 6 | * @author zhaojh 7 | */ 8 | public interface SessionIdManager extends LifeCycle{ 9 | String newSessionId(HttpServletRequest request,long created); 10 | } 11 | -------------------------------------------------------------------------------- /10.5-servlet3.x-directory-structure/src/main/resources/META-INF/resources/views/greeting.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

Hello Everyone!

10 | 11 | 12 | -------------------------------------------------------------------------------- /simple-distributed-sessions-manager/src/main/java/com/github/loafer/distributed/httpsession/SessionIDManager.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.distributed.httpsession; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | 5 | /** 6 | * @author zhaojh 7 | */ 8 | public interface SessionIDManager extends LifeCycle{ 9 | String newSessionId(HttpServletRequest request,long created); 10 | } 11 | -------------------------------------------------------------------------------- /10.5-servlet3.x-directory-structure/src/main/resources/META-INF/resources/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

Hello World!

11 | 12 | 13 | -------------------------------------------------------------------------------- /servlet2.x-webapp/src/main/webapp/WEB-INF/views/greeting.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | <%@page import="com.github.loafer.bean.User" %> 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

Hello, <%=((User)request.getSession().getAttribute("user")).getName()%>

11 | 12 | 13 | -------------------------------------------------------------------------------- /servlet3.x-webapp/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

Hello Servlet 3.0!

12 | 13 | 14 | -------------------------------------------------------------------------------- /servlet3.x-webapp/src/main/webapp/WEB-INF/weblogic.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | /app1 14 | 15 | 16 | 17 | true 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /simple-distributed-sessions-manager/src/main/java/com/github/loafer/distributed/httpsession/SessionManager.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.distributed.httpsession; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import javax.servlet.http.HttpSession; 5 | 6 | /** 7 | * @author zhaojh 8 | */ 9 | public interface SessionManager extends LifeCycle{ 10 | String DISTRIBUTED_SESSION_ID = "JSESSIONID"; 11 | 12 | HttpSession newHttpSession(HttpServletRequest request); 13 | HttpSession getHttpSession(String id); 14 | boolean isValid(HttpSession session); 15 | void removeHttpSession(HttpSession session); 16 | SessionStorage getSessionStorage(); 17 | } 18 | -------------------------------------------------------------------------------- /webapp/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.github.loafer 6 | webapp 7 | war 8 | 1.0-SNAPSHOT 9 | 10 | 11 | 12 | 13 | 14 | com.github.loafer 15 | servlet3.x-directory-structure 16 | 1.0-SNAPSHOT 17 | 18 | 19 | 20 | 21 | webapp 22 | 23 | 24 | -------------------------------------------------------------------------------- /servlet3.x-session/src/main/java/com/github/loafer/session/SessionStore.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.session; 2 | 3 | import com.github.loafer.session.metadata.SessionMetaData; 4 | 5 | import javax.servlet.http.HttpSession; 6 | import java.util.List; 7 | 8 | /** 9 | * @author zhaojh 10 | */ 11 | public interface SessionStore extends LifeCycle{ 12 | void putSessionMetaData(HttpSession session); 13 | SessionMetaData getSessionMetaData(String sessionid); 14 | void removeSessionMetaData(String sessionid); 15 | void updateSessionMetaData(String sessionid, String name, Object value); 16 | 17 | void setAttribute(String sessionid, String name, Object value); 18 | void removeAttribute(String sessionid, String name); 19 | Object getAttribute(String sessionid, String name); 20 | List getAttributeNames(String sessionid); 21 | } 22 | -------------------------------------------------------------------------------- /servlet2.x-webapp/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | Archetype Created Web Application 7 | 8 | 9 | com.github.loafer.listener.HttpSessionLifecycle 10 | 11 | 12 | 13 | greeting 14 | com.github.loafer.servlet.GreetingServlet 15 | 16 | 17 | 18 | greeting 19 | /greeting 20 | 21 | 22 | 23 | 1 24 | 25 | 26 | -------------------------------------------------------------------------------- /servlet2.x-webapp/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.github.loafer 6 | servlet2.x-webapp 7 | war 8 | 1.0-SNAPSHOT 9 | 10 | servlet2.x-webapp 11 | http://maven.apache.org 12 | 13 | 14 | 15 | com.github.loafer 16 | servlet2.x-session 17 | 1.0-SNAPSHOT 18 | 19 | 20 | 21 | 22 | servlet2.x-webapp 23 | 24 | 25 | -------------------------------------------------------------------------------- /servlet3.x-servletContainerInitializer/src/main/java/com/github/loafer/servlet/WebApplicationInitializer.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.servlet; 2 | 3 | import javax.servlet.ServletContainerInitializer; 4 | import javax.servlet.ServletContext; 5 | import javax.servlet.ServletException; 6 | import javax.servlet.ServletRegistration; 7 | import java.util.Set; 8 | 9 | /** 10 | * 动态注册servlet 11 | * 注意: 12 | * 1、在META-INF/services/中放入javax.servlet.ServletContainerInitializer文件 13 | * 2、只会在容器启动时加载一次 14 | * @author zhaojh 15 | */ 16 | public class WebApplicationInitializer implements ServletContainerInitializer { 17 | 18 | @Override 19 | public void onStartup(Set> classes, ServletContext servletContext) throws ServletException { 20 | ServletRegistration.Dynamic dynamic = servletContext.addServlet("greeting", GreetingServlet.class); 21 | dynamic.addMapping("/greeting"); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /servlet3.x-session/src/main/java/com/github/loafer/session/SessionManager.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.session; 2 | 3 | import org.slf4j.Logger; 4 | 5 | import javax.servlet.ServletContext; 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | import javax.servlet.http.HttpSession; 9 | 10 | /** 11 | * @author zhaojh 12 | */ 13 | public interface SessionManager extends LifeCycle{ 14 | String DISTRIBUTED_SESSION_ID = "JDSESSIONID"; 15 | 16 | void add(HttpSession session); 17 | void remove(HttpSession session); 18 | void setMaxInactiveInterval(int interval); 19 | HttpSession newHttpSession(HttpServletRequest request, HttpServletResponse response); 20 | HttpSession getHttpSession(String id); 21 | ServletContext getServletContext(); 22 | String getRequestedSessionId(HttpServletRequest request); 23 | SessionStore getSessionStore(); 24 | } 25 | -------------------------------------------------------------------------------- /10.5-servlet3.x-directory-structure/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.github.loafer 6 | servlet3.x-directory-structure 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | servlet3.x-directory-structure 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | 19 | javax.servlet 20 | javax.servlet-api 21 | 3.1.0 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /servlet3.x-servletContainerInitializer/src/main/java/com/github/loafer/servlet/CustomServletContextListener.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.servlet; 2 | 3 | import javax.servlet.ServletContext; 4 | import javax.servlet.ServletContextEvent; 5 | import javax.servlet.ServletContextListener; 6 | import javax.servlet.ServletRegistration; 7 | 8 | /** 9 | * 动态注册servlet 10 | * 注意: 11 | * 1、只会在容器启动时加载一次 12 | * 13 | * @author zhaojh 14 | */ 15 | public class CustomServletContextListener implements ServletContextListener{ 16 | @Override 17 | public void contextInitialized(ServletContextEvent servletContextEvent) { 18 | ServletContext context = servletContextEvent.getServletContext(); 19 | ServletRegistration.Dynamic dynamic = context.addServlet("greeting", GreetingServlet.class); 20 | dynamic.addMapping("/greeting"); 21 | } 22 | 23 | @Override 24 | public void contextDestroyed(ServletContextEvent servletContextEvent) { 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /servlet3.x-webapp/src/main/java/com/github/loafer/servlet/HelloServlet.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.servlet; 2 | 3 | import javax.servlet.ServletException; 4 | import javax.servlet.http.HttpServlet; 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | import java.io.IOException; 8 | import java.net.URL; 9 | 10 | /** 11 | * @author zhaojh. 12 | */ 13 | public class HelloServlet extends HttpServlet { 14 | 15 | @Override 16 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 17 | doPost(request, response); 18 | } 19 | 20 | @Override 21 | protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 22 | URL root = Thread.currentThread().getContextClassLoader().getResource("/"); 23 | System.out.println("HelloServlet ====> " + root.toString()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /servlet2.x-session/src/main/java/com/github/loafer/listener/HttpSessionLifecycle.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.listener; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import javax.servlet.http.HttpSession; 7 | import javax.servlet.http.HttpSessionEvent; 8 | import javax.servlet.http.HttpSessionListener; 9 | 10 | /** 11 | * @author zhaojh 12 | */ 13 | public class HttpSessionLifecycle implements HttpSessionListener { 14 | private static final Logger logger = LoggerFactory.getLogger(HttpSessionLifecycle.class); 15 | 16 | @Override 17 | public void sessionCreated(HttpSessionEvent event) { 18 | HttpSession session = event.getSession(); 19 | logger.info("HttpSession [{}] 被创建。", session.getId()); 20 | } 21 | 22 | @Override 23 | public void sessionDestroyed(HttpSessionEvent event) { 24 | HttpSession session = event.getSession(); 25 | logger.info("HttpSession [{}] 已销毁。", session.getId()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /simple-distributed-sessions-manager/src/main/java/com/github/loafer/greeting/GreetingServlet.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.greeting; 2 | 3 | import javax.servlet.RequestDispatcher; 4 | import javax.servlet.ServletException; 5 | import javax.servlet.http.HttpServlet; 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | import java.io.IOException; 9 | 10 | /** 11 | * Created by zhaojh on 14-10-22. 12 | */ 13 | public class GreetingServlet extends HttpServlet { 14 | @Override 15 | protected void doGet(HttpServletRequest request, HttpServletResponse response) 16 | throws ServletException, IOException { 17 | 18 | String name = request.getParameter("name"); 19 | if(null != name){ 20 | request.getSession().setAttribute("name", name); 21 | } 22 | RequestDispatcher dispatcher = request.getRequestDispatcher("WEB-INF/views/greeting.jsp"); 23 | dispatcher.forward(request, response); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /servlet3.x-session/src/main/java/com/github/loafer/servlet/GreetingServlet.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.servlet; 2 | 3 | import javax.servlet.RequestDispatcher; 4 | import javax.servlet.ServletException; 5 | import javax.servlet.http.HttpServlet; 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | import java.io.IOException; 9 | 10 | /** 11 | * @author zhaojh 12 | */ 13 | public class GreetingServlet extends HttpServlet { 14 | @Override 15 | protected void doPost(HttpServletRequest request, HttpServletResponse response) 16 | throws ServletException, IOException { 17 | doGet(request, response); 18 | } 19 | 20 | @Override 21 | protected void doGet(HttpServletRequest request, HttpServletResponse response) 22 | throws ServletException, IOException { 23 | request.getSession().setAttribute("hello", "balabala~~"); 24 | RequestDispatcher dispatcher = request.getRequestDispatcher("WEB-INF/views/greeting.jsp"); 25 | dispatcher.forward(request, response); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /servlet3.x-webapp/src/main/webapp/WEB-INF/views/greeting.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" session="true" %> 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

Welcome Everyone!

10 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /servlet3.x-session/src/main/java/com/github/loafer/session/metadata/SessionMetaData.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.session.metadata; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author zhaojh 7 | */ 8 | public class SessionMetaData implements Serializable{ 9 | private String id; 10 | private long creationTime; 11 | private long lastAccessedTime; 12 | private int maxInactiveInterval; 13 | 14 | public SessionMetaData(String id, long creationTime, long lastAccessedTime, int maxInactiveInterval) { 15 | this.id = id; 16 | this.creationTime = creationTime; 17 | this.lastAccessedTime = lastAccessedTime; 18 | this.maxInactiveInterval = maxInactiveInterval; 19 | } 20 | 21 | public String getId() { 22 | return id; 23 | } 24 | 25 | public long getCreationTime() { 26 | return creationTime; 27 | } 28 | 29 | 30 | public long getLastAccessedTime() { 31 | return lastAccessedTime; 32 | } 33 | 34 | 35 | public int getMaxInactiveInterval() { 36 | return maxInactiveInterval; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /servlet2.x-session/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.github.loafer 6 | servlet2.x-session 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | servlet2.x-session 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | 19 | javax.servlet 20 | servlet-api 21 | 2.4 22 | provided 23 | 24 | 25 | 26 | org.slf4j 27 | slf4j-simple 28 | 1.7.5 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /simple-distributed-sessions-manager/src/main/java/com/github/loafer/distributed/httpsession/SessionStorage.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.distributed.httpsession; 2 | 3 | import com.github.loafer.distributed.httpsession.metadata.SessionMetaData; 4 | 5 | import javax.servlet.http.HttpSession; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | /** 10 | * @author zhaojh 11 | */ 12 | public interface SessionStorage extends LifeCycle{ 13 | boolean isStored(HttpSession session); 14 | void storeSessionMetaData(HttpSession session); 15 | SessionMetaData getSessionMetaData(String sessionid); 16 | void updateSessionMetaDataField(String sessionid, String name, Object value); 17 | Object getSessionMetaDataField(String sessionid, String name); 18 | void removeSession(String sessionid); 19 | 20 | void storeSessionAttribute(String sessionid, String name, Object value); 21 | void removeSessionAttribute(String sessionid, String name); 22 | Object getSessionAttribute(String sessionid, String name); 23 | List getSessionAttributeNames(String sessionid); 24 | Map getSessionAttributes(String sessionid); 25 | } 26 | -------------------------------------------------------------------------------- /servlet3.x-servletContainerInitializer/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.github.loafer 6 | servlet3.x-servletContainerInitializer 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | servlet3.x-servletContainerInitializer 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | 19 | javax.servlet 20 | javax.servlet-api 21 | 3.1.0 22 | 23 | 24 | 25 | com.github.loafer 26 | servlet3.x-directory-structure 27 | 1.0-SNAPSHOT 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /simple-distributed-sessions-manager/src/main/java/com/github/loafer/distributed/httpsession/manager/task/ClearInvalidSessionScheduledTask.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.distributed.httpsession.manager.task; 2 | 3 | import com.github.loafer.distributed.httpsession.session.DistributedHttpSession; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import javax.servlet.http.HttpSession; 8 | import java.util.Map; 9 | 10 | /** 11 | * @author zhaojh 12 | */ 13 | public class ClearInvalidSessionScheduledTask implements Runnable{ 14 | private static final Logger logger = LoggerFactory.getLogger(ClearInvalidSessionScheduledTask.class); 15 | private Map localSessionContainer; 16 | 17 | public ClearInvalidSessionScheduledTask(Map localSessionContainer) { 18 | this.localSessionContainer = localSessionContainer; 19 | } 20 | 21 | @Override 22 | public void run() { 23 | // logger.info("执行清除过期Session任务。"); 24 | for (HttpSession session: localSessionContainer.values()){ 25 | if(!((DistributedHttpSession)session).isValid()){ 26 | logger.info("Clear session[{}]", session.getId()); 27 | session.invalidate(); 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /simple-distributed-sessions-manager/src/main/java/com/github/loafer/distributed/httpsession/manager/task/ClearInvalidSessionTask.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.distributed.httpsession.manager.task; 2 | 3 | import com.github.loafer.distributed.httpsession.session.DistributedHttpSession; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import javax.servlet.http.HttpSession; 8 | import java.util.concurrent.TimeUnit; 9 | 10 | /** 11 | * @author zhaojh 12 | */ 13 | public class ClearInvalidSessionTask implements Runnable{ 14 | private static final Logger logger = LoggerFactory.getLogger(ClearInvalidSessionTask.class); 15 | private static final int SLEEP_TIME = 10; 16 | private HttpSession session; 17 | 18 | public ClearInvalidSessionTask(HttpSession session) { 19 | this.session = session; 20 | } 21 | 22 | @Override 23 | public void run() { 24 | while (true){ 25 | try { 26 | if(((DistributedHttpSession)session).isValid()){ 27 | session.invalidate(); 28 | break; 29 | } 30 | TimeUnit.SECONDS.sleep(SLEEP_TIME); 31 | } catch (InterruptedException e) { 32 | e.printStackTrace(); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /servlet3.x-session/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.github.loafer 6 | servlet3.x-session 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | servlet3.x-session 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | 19 | javax.servlet 20 | javax.servlet-api 21 | 3.1.0 22 | provided 23 | 24 | 25 | 26 | org.slf4j 27 | slf4j-simple 28 | 1.7.5 29 | 30 | 31 | 32 | redis.clients 33 | jedis 34 | 2.6.0 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /simple-distributed-sessions-manager/src/main/java/com/github/loafer/distributed/httpsession/metadata/SessionMetaData.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.distributed.httpsession.metadata; 2 | 3 | /** 4 | * @author zhaojh 5 | */ 6 | public class SessionMetaData { 7 | public static final String CREATION_TIME_KEY = "creationTime"; 8 | public static final String LAST_ACCESSED_TIME_KEY = "lastAccessedTime"; 9 | public static final String MAX_INACTIVE_INTERVAL_KEY = "maxInactiveInterval"; 10 | 11 | private String id; 12 | private long creationTime; 13 | private long lastAccessedTime; 14 | private int maxInactiveInterval; 15 | 16 | public SessionMetaData(String id, long creationTime, long lastAccessedTime, int maxInactiveInterval) { 17 | this.id = id; 18 | this.creationTime = creationTime; 19 | this.lastAccessedTime = lastAccessedTime; 20 | this.maxInactiveInterval = maxInactiveInterval; 21 | } 22 | 23 | public String getId() { 24 | return id; 25 | } 26 | 27 | public long getCreationTime() { 28 | return creationTime; 29 | } 30 | 31 | 32 | public long getLastAccessedTime() { 33 | return lastAccessedTime; 34 | } 35 | 36 | 37 | public int getMaxInactiveInterval() { 38 | return maxInactiveInterval; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /10.5-servlet3.x-directory-structure/src/main/java/com/github/loafer/servlet/GreetingServlet.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.servlet; 2 | 3 | 4 | import javax.servlet.RequestDispatcher; 5 | import javax.servlet.ServletException; 6 | import javax.servlet.http.HttpServlet; 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.servlet.http.HttpServletResponse; 9 | import javax.servlet.http.HttpSession; 10 | import java.io.IOException; 11 | import java.net.URL; 12 | 13 | /** 14 | * @author zhaojh 15 | */ 16 | public class GreetingServlet extends HttpServlet { 17 | @Override 18 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 19 | doPost(req, resp); 20 | } 21 | 22 | @Override 23 | protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 24 | URL root = Thread.currentThread().getContextClassLoader().getResource("/"); 25 | System.out.println("GreetingServlet ====> " + root.toString()); 26 | 27 | HttpSession session = request.getSession(); 28 | session.setAttribute("hello", "balabala~~~"); 29 | RequestDispatcher dispatcher = request.getRequestDispatcher("/WEB-INF/views/greeting.jsp"); 30 | dispatcher.forward(request, response); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /servlet2.x-session/src/main/java/com/github/loafer/servlet/GreetingServlet.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.servlet; 2 | 3 | import com.github.loafer.bean.User; 4 | 5 | import javax.servlet.RequestDispatcher; 6 | import javax.servlet.ServletException; 7 | import javax.servlet.http.HttpServlet; 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import javax.servlet.http.HttpSession; 11 | import java.io.IOException; 12 | 13 | /** 14 | * @author zhaojh 15 | */ 16 | public class GreetingServlet extends HttpServlet { 17 | @Override 18 | protected void doPost(HttpServletRequest request, HttpServletResponse response) 19 | throws ServletException, IOException { 20 | HttpSession session = request.getSession(); 21 | String name = request.getParameter("name"); 22 | if(null != name){ 23 | User user = new User(name); 24 | session.setAttribute("user", user); 25 | } 26 | 27 | RequestDispatcher dispatcher = request.getRequestDispatcher("WEB-INF/views/greeting.jsp"); 28 | dispatcher.forward(request, response); 29 | } 30 | 31 | @Override 32 | protected void doGet(HttpServletRequest request, HttpServletResponse response) 33 | throws ServletException, IOException { 34 | doPost(request, response); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /servlet3.x-session/src/main/java/com/github/loafer/util/SerializationUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.util; 2 | 3 | import java.io.*; 4 | 5 | /** 6 | * @author zhaojh 7 | */ 8 | public abstract class SerializationUtils { 9 | public static byte[] serialize(Object object) { 10 | if (object == null) { 11 | return null; 12 | } 13 | ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); 14 | try { 15 | ObjectOutputStream oos = new ObjectOutputStream(baos); 16 | oos.writeObject(object); 17 | oos.flush(); 18 | } 19 | catch (IOException ex) { 20 | throw new IllegalArgumentException("Failed to serialize object of type: " + object.getClass(), ex); 21 | } 22 | return baos.toByteArray(); 23 | } 24 | 25 | public static Object deserialize(byte[] bytes) { 26 | if (bytes == null) { 27 | return null; 28 | } 29 | try { 30 | ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes)); 31 | return ois.readObject(); 32 | } 33 | catch (IOException ex) { 34 | throw new IllegalArgumentException("Failed to deserialize object", ex); 35 | } 36 | catch (ClassNotFoundException ex) { 37 | throw new IllegalStateException("Failed to deserialize object type", ex); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /simple-distributed-sessions-manager/src/main/java/com/github/loafer/distributed/httpsession/util/SerializationUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.distributed.httpsession.util; 2 | 3 | import java.io.*; 4 | 5 | /** 6 | * @author zhaojh 7 | */ 8 | public abstract class SerializationUtils { 9 | public static byte[] serialize(Object object) { 10 | if (object == null) { 11 | return null; 12 | } 13 | ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); 14 | try { 15 | ObjectOutputStream oos = new ObjectOutputStream(baos); 16 | oos.writeObject(object); 17 | oos.flush(); 18 | } 19 | catch (IOException ex) { 20 | throw new IllegalArgumentException("Failed to serialize object of type: " + object.getClass(), ex); 21 | } 22 | return baos.toByteArray(); 23 | } 24 | 25 | public static Object deserialize(byte[] bytes) { 26 | if (bytes == null) { 27 | return null; 28 | } 29 | try { 30 | ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes)); 31 | return ois.readObject(); 32 | } 33 | catch (IOException ex) { 34 | throw new IllegalArgumentException("Failed to deserialize object", ex); 35 | } 36 | catch (ClassNotFoundException ex) { 37 | throw new IllegalStateException("Failed to deserialize object type", ex); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /servlet3.x-webapp/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 4.0.0 5 | com.github.loafer 6 | servlet3.x-webapp 7 | war 8 | 1.0-SNAPSHOT 9 | 10 | servlet3.x-webapp 11 | http://maven.apache.org 12 | 13 | 14 | servlet3.x-webapp 15 | 16 | 17 | 18 | 19 | 20 | com.github.loafer 21 | servlet3.x-directory-structure 22 | 1.0-SNAPSHOT 23 | 24 | 25 | 26 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /servlet2.x-session/src/main/java/com/github/loafer/bean/User.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.bean; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import javax.servlet.http.HttpSessionBindingEvent; 7 | import javax.servlet.http.HttpSessionBindingListener; 8 | 9 | /** 10 | * @author zhaojh 11 | */ 12 | public class User implements HttpSessionBindingListener{ 13 | private static final Logger logger = LoggerFactory.getLogger(User.class); 14 | private long id; 15 | private String name; 16 | private int age; 17 | 18 | public User(String name) { 19 | this.id = System.currentTimeMillis(); 20 | this.name = name; 21 | } 22 | 23 | public long getId() { 24 | return id; 25 | } 26 | 27 | public String getName() { 28 | return name; 29 | } 30 | 31 | public int getAge() { 32 | return age; 33 | } 34 | 35 | public void setAge(int age) { 36 | this.age = age; 37 | } 38 | 39 | @Override 40 | public void valueBound(HttpSessionBindingEvent event) { 41 | logger.info("用户 [{}] 的信息将被绑定在session[{}]中", this.name, event.getSession().getId()); 42 | } 43 | 44 | @Override 45 | public void valueUnbound(HttpSessionBindingEvent event) { 46 | logger.info("用户 [{}] 的信息已被从session[{}]中删除", this.name, event.getSession().getId()); 47 | } 48 | 49 | @Override 50 | public boolean equals(Object o) { 51 | if (this == o) return true; 52 | if (o == null || getClass() != o.getClass()) return false; 53 | 54 | User user = (User) o; 55 | 56 | if (id != user.id) return false; 57 | 58 | return true; 59 | } 60 | 61 | @Override 62 | public int hashCode() { 63 | return (int) (id ^ (id >>> 32)); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /servlet3.x-session/src/main/java/com/github/loafer/helper/CookieHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.helper; 2 | 3 | import com.github.loafer.session.SessionManager; 4 | 5 | import javax.servlet.http.Cookie; 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | 9 | /** 10 | * @author zhaojh 11 | */ 12 | public class CookieHelper { 13 | public static void writeSessionIdToCookie(String id, 14 | HttpServletRequest request, 15 | HttpServletResponse response){ 16 | 17 | // Cookie cookie = findCookie(SessionManager.DISTRIBUTED_SESSION_ID, request); 18 | // if(null == cookie){ 19 | // cookie = new Cookie(SessionManager.DISTRIBUTED_SESSION_ID, id); 20 | // response.addCookie(cookie); 21 | // } 22 | Cookie cookie = new Cookie(SessionManager.DISTRIBUTED_SESSION_ID, id); 23 | response.addCookie(cookie); 24 | } 25 | 26 | public static String findSessionId(HttpServletRequest request){ 27 | return findCookieValue(SessionManager.DISTRIBUTED_SESSION_ID, request); 28 | } 29 | 30 | private static Cookie findCookie(String name, HttpServletRequest request){ 31 | Cookie[] cookies = request.getCookies(); 32 | if(null == cookies) return null; 33 | 34 | for (Cookie cookie : cookies){ 35 | if (cookie.getName().equals(name)) 36 | return cookie; 37 | } 38 | 39 | return null; 40 | } 41 | 42 | private static String findCookieValue(String name, HttpServletRequest request) { 43 | Cookie cookie = findCookie(name, request); 44 | if (cookie != null) { 45 | return cookie.getValue(); 46 | } 47 | return null; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /simple-distributed-sessions-manager/src/main/java/com/github/loafer/distributed/httpsession/helper/CookieHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.distributed.httpsession.helper; 2 | 3 | import com.github.loafer.distributed.httpsession.SessionManager; 4 | 5 | import javax.servlet.http.Cookie; 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | 9 | /** 10 | * @author zhaojh 11 | */ 12 | public abstract class CookieHelper { 13 | public static void writeSessionIdToCookie(String id, 14 | HttpServletRequest request, 15 | HttpServletResponse response){ 16 | 17 | // Cookie cookie = findCookie(SessionManager.DISTRIBUTED_SESSION_ID, request); 18 | // if(null == cookie){ 19 | // cookie = new Cookie(SessionManager.DISTRIBUTED_SESSION_ID, id); 20 | // response.addCookie(cookie); 21 | // } 22 | Cookie cookie = new Cookie(SessionManager.DISTRIBUTED_SESSION_ID, id); 23 | response.addCookie(cookie); 24 | } 25 | 26 | public static String findSessionId(HttpServletRequest request){ 27 | return findCookieValue(SessionManager.DISTRIBUTED_SESSION_ID, request); 28 | } 29 | 30 | private static Cookie findCookie(String name, HttpServletRequest request){ 31 | Cookie[] cookies = request.getCookies(); 32 | if(null == cookies) return null; 33 | 34 | for (Cookie cookie : cookies){ 35 | if (cookie.getName().equals(name)) 36 | return cookie; 37 | } 38 | 39 | return null; 40 | } 41 | 42 | private static String findCookieValue(String name, HttpServletRequest request) { 43 | Cookie cookie = findCookie(name, request); 44 | if (cookie != null) { 45 | return cookie.getValue(); 46 | } 47 | return null; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /servlet3.x-webapp/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 14 | 15 | 55 | 56 | -------------------------------------------------------------------------------- /simple-distributed-sessions-manager/src/main/java/com/github/loafer/distributed/httpsession/manager/NoStickySessionManager.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.distributed.httpsession.manager; 2 | 3 | import com.github.loafer.distributed.httpsession.metadata.SessionMetaData; 4 | import com.github.loafer.distributed.httpsession.session.DistributedHttpSession; 5 | import com.github.loafer.distributed.httpsession.session.NoStickyHttpSession; 6 | import com.github.loafer.distributed.httpsession.session.StickyHttpSession; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import javax.servlet.ServletContext; 11 | import javax.servlet.http.HttpSession; 12 | 13 | /** 14 | * @author zhaojh 15 | */ 16 | public class NoStickySessionManager extends AbstractSessionManager { 17 | private static final Logger logger = LoggerFactory.getLogger(NoStickySessionManager.class); 18 | 19 | public NoStickySessionManager(ServletContext servletContext, int maxInactiveInterval) { 20 | super(servletContext, maxInactiveInterval); 21 | } 22 | 23 | @Override 24 | protected HttpSession newHttpSession(String id, int maxInactiveInterval, ServletContext servletContext) { 25 | return new NoStickyHttpSession(id, maxInactiveInterval, this, servletContext); 26 | } 27 | 28 | @Override 29 | protected HttpSession findHttpSession(String id) { 30 | //local 31 | HttpSession session = findSessionFromLocal(id); 32 | if(null != session){ 33 | return session; 34 | }else{ 35 | logger.info("本地没有session[{}]的信息。", id); 36 | } 37 | 38 | SessionMetaData metaData = getSessionMetaDataFromStorage(id); 39 | if(null != metaData){ 40 | logger.debug("Session Storage中持有session[{}]的信息.", id); 41 | session = new NoStickyHttpSession( 42 | id, 43 | metaData.getCreationTime(), 44 | metaData.getLastAccessedTime(), 45 | metaData.getMaxInactiveInterval(), 46 | this, 47 | getServletContext() 48 | ); 49 | } 50 | return session; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /simple-distributed-sessions-manager/src/main/java/com/github/loafer/distributed/httpsession/manager/StickySessionManager.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.distributed.httpsession.manager; 2 | 3 | import com.github.loafer.distributed.httpsession.metadata.SessionMetaData; 4 | import com.github.loafer.distributed.httpsession.session.DistributedHttpSession; 5 | import com.github.loafer.distributed.httpsession.session.StickyHttpSession; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import javax.servlet.ServletContext; 10 | import javax.servlet.http.HttpSession; 11 | 12 | /** 13 | * @author zhaojh 14 | */ 15 | public class StickySessionManager extends AbstractSessionManager{ 16 | private static final Logger logger = LoggerFactory.getLogger(StickySessionManager.class); 17 | 18 | public StickySessionManager(ServletContext servletContext, int maxInactiveInterval) { 19 | super(servletContext, maxInactiveInterval); 20 | } 21 | 22 | @Override 23 | protected HttpSession newHttpSession(String id, int maxInactiveInterval, ServletContext servletContext) { 24 | return new StickyHttpSession(id, maxInactiveInterval, this, servletContext); 25 | } 26 | 27 | @Override 28 | public HttpSession findHttpSession(String id) { 29 | //local 30 | HttpSession session = findSessionFromLocal(id); 31 | if(null != session){ 32 | return session; 33 | }else{ 34 | logger.info("本地没有session[{}]的信息。", id); 35 | } 36 | 37 | //storage 38 | SessionMetaData metaData = getSessionMetaDataFromStorage(id); 39 | if(null != metaData){ 40 | logger.debug("Session Storage中持有session[{}]的信息.", id); 41 | session = new StickyHttpSession( 42 | id, 43 | metaData.getCreationTime(), 44 | metaData.getLastAccessedTime(), 45 | metaData.getMaxInactiveInterval(), 46 | this, 47 | getServletContext() 48 | ); 49 | 50 | logger.info("根据Session Storage中的信息构建session[{}].", id); 51 | ((DistributedHttpSession)session).refresh(); 52 | } 53 | 54 | logger.debug("未找到Session[{}]", id); 55 | return session; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /simple-distributed-sessions-manager/src/main/java/com/github/loafer/distributed/httpsession/manager/DefaultSessionIDManager.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.distributed.httpsession.manager; 2 | 3 | import com.github.loafer.distributed.httpsession.SessionIDManager; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import javax.servlet.http.HttpServletRequest; 8 | import java.security.SecureRandom; 9 | import java.util.Random; 10 | 11 | /** 12 | * @author zhaojh 13 | */ 14 | public class DefaultSessionIDManager implements SessionIDManager { 15 | private static final Logger logger = LoggerFactory.getLogger(DefaultSessionIDManager.class); 16 | 17 | // private final static String __NEW_SESSION_ID = "com.github.loafer.newSessionId"; 18 | private Random random; 19 | private boolean weakRandom; 20 | private long reseed=100000L; 21 | 22 | @Override 23 | public String newSessionId(HttpServletRequest request, long created) { 24 | if(request == null){ 25 | return newSessionId(created); 26 | } 27 | 28 | return newSessionId(request.hashCode()); 29 | } 30 | 31 | @Override 32 | public void start() { 33 | logger.info("启动Session ID Manager."); 34 | try{ 35 | random = new SecureRandom(); 36 | }catch (Exception e){ 37 | logger.warn("Could not generate SecureRandom for httpsession-id randomness", e); 38 | random = new Random(); 39 | weakRandom = true; 40 | } 41 | } 42 | 43 | @Override 44 | public void stop() { 45 | 46 | } 47 | 48 | private String newSessionId(long seedTerm){ 49 | String id = null; 50 | while (id == null || id.length() == 0){ 51 | long r0 = weakRandom ? (hashCode() ^ Runtime.getRuntime().freeMemory() ^ random.nextInt() ^ (seedTerm<<32)) 52 | : random.nextLong(); 53 | 54 | if(r0 < 0) r0 = -r0; 55 | 56 | if (reseed>0 && (r0 % reseed)== 1L){ 57 | logger.info("Reseeding {}", this); 58 | 59 | if(random instanceof SecureRandom){ 60 | SecureRandom secure = (SecureRandom) random; 61 | secure.setSeed(secure.generateSeed(8)); 62 | }else{ 63 | random.setSeed(random.nextLong() ^ System.currentTimeMillis() ^ seedTerm ^ Runtime.getRuntime().freeMemory()); 64 | } 65 | } 66 | 67 | long r1 = weakRandom ? 68 | (hashCode() ^ Runtime.getRuntime().freeMemory() ^ random.nextInt() ^ (seedTerm<<32)) 69 | : random.nextLong(); 70 | 71 | if(r1 < 0) r1 = -r1; 72 | 73 | id = Long.toString(r0, 36) + Long.toString(r1, 36); 74 | } 75 | 76 | return id + ".quick4j"; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /servlet3.x-session/src/main/java/com/github/loafer/session/support/RedisHttpSession.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.session.support; 2 | 3 | import com.github.loafer.session.SessionManager; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import javax.servlet.http.HttpSessionBindingEvent; 8 | import javax.servlet.http.HttpSessionBindingListener; 9 | import java.util.Collections; 10 | import java.util.Enumeration; 11 | import java.util.Map; 12 | import java.util.concurrent.ConcurrentHashMap; 13 | 14 | /** 15 | * @author zhaojh 16 | */ 17 | public class RedisHttpSession extends AbstractDistributedHttpSession { 18 | private static final Logger logger = LoggerFactory.getLogger(RedisHttpSession.class); 19 | public RedisHttpSession(String id, 20 | long creationTm, 21 | long lastAccessedTm, 22 | int maxInactiveInterval, 23 | SessionManager sessionManager) { 24 | super(id, creationTm, lastAccessedTm, maxInactiveInterval, sessionManager); 25 | } 26 | 27 | public RedisHttpSession(String id, int maxInactiveInterval, SessionManager sessionManager) { 28 | super(id, maxInactiveInterval, sessionManager); 29 | } 30 | 31 | @Override 32 | public Object getAttribute(String name) { 33 | access(false); 34 | return sessionStore.getAttribute(getId(), name); 35 | } 36 | 37 | @Override 38 | public Enumeration getAttributeNames() { 39 | access(false); 40 | return Collections.enumeration(sessionStore.getAttributeNames(getId())); 41 | } 42 | 43 | @Override 44 | public void setAttribute(String name, Object value) { 45 | access(true); 46 | 47 | Object oldValue = sessionStore.getAttribute(getId(), name); 48 | if(value instanceof HttpSessionBindingListener){ 49 | if(value != oldValue){ 50 | try{ 51 | ((HttpSessionBindingListener)value).valueBound(new HttpSessionBindingEvent(this, name, value)); 52 | }catch (Exception e){ 53 | logger.error("bingEvent error:", e); 54 | } 55 | } 56 | } 57 | 58 | sessionStore.setAttribute(getId(), name, value); 59 | 60 | if(oldValue != null && oldValue != value && 61 | oldValue instanceof HttpSessionBindingListener){ 62 | try{ 63 | ((HttpSessionBindingListener)oldValue).valueUnbound(new HttpSessionBindingEvent(this, name)); 64 | }catch (Exception e){ 65 | logger.error("bingEvent error:", e); 66 | } 67 | } 68 | } 69 | 70 | @Override 71 | public void removeAttribute(String name) { 72 | access(false); 73 | sessionStore.removeAttribute(getId(), name); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /servlet3.x-session/src/main/java/com/github/loafer/filter/DistributableSessionFilter.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.filter; 2 | 3 | import com.github.loafer.session.SessionManager; 4 | import com.github.loafer.session.support.SessionManagerImpl; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import javax.servlet.*; 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletRequestWrapper; 11 | import javax.servlet.http.HttpServletResponse; 12 | import javax.servlet.http.HttpSession; 13 | import java.io.IOException; 14 | 15 | /** 16 | * @author zhaojh 17 | */ 18 | public class DistributableSessionFilter implements Filter{ 19 | private static Logger logger = LoggerFactory.getLogger(DistributableSessionFilter.class); 20 | private SessionManager sessionManager; 21 | 22 | @Override 23 | public void init(FilterConfig filterConfig) throws ServletException { 24 | sessionManager = new SessionManagerImpl(filterConfig.getServletContext()); 25 | sessionManager.start(); 26 | } 27 | 28 | @Override 29 | public void doFilter(final ServletRequest request, 30 | final ServletResponse response, 31 | FilterChain chain) 32 | throws IOException, ServletException { 33 | 34 | final HttpServletRequest httpRequest = (HttpServletRequest) request; 35 | final HttpServletResponse httpReponse = (HttpServletResponse) response; 36 | 37 | logger.info("servlet path: {}",((HttpServletRequest) request).getServletPath()); 38 | logger.info("cookies: {}", ((HttpServletRequest) request).getCookies()); 39 | 40 | HttpServletRequest newRequest = new HttpServletRequestWrapper(httpRequest){ 41 | @Override 42 | public HttpSession getSession(boolean create) { 43 | HttpSession session = null; 44 | 45 | //查找与当前requset关联的session 46 | String sessionid = sessionManager.getRequestedSessionId(httpRequest); 47 | logger.info("=========================================="); 48 | logger.info("与当前请求相关联的session为[{}]。", sessionid); 49 | if(sessionid != null){ 50 | session = sessionManager.getHttpSession(sessionid); 51 | if(session != null){ 52 | logger.info("检索到[{}]标记的session。", sessionid); 53 | }else{ 54 | logger.info("没有检索到[{}]标记的session。", sessionid); 55 | } 56 | } 57 | 58 | //如果session不存在,并且create=true,则创建新session,否则返回null 59 | if(session == null && create){ 60 | session = sessionManager.newHttpSession(httpRequest, httpReponse); 61 | logger.info("创建一个新session[{}]。", session.getId()); 62 | } 63 | 64 | logger.info("=========================================="); 65 | return session; 66 | } 67 | 68 | @Override 69 | public HttpSession getSession() { 70 | return getSession(true); 71 | } 72 | }; 73 | 74 | chain.doFilter(newRequest, response); 75 | } 76 | 77 | @Override 78 | public void destroy() { 79 | sessionManager.stop(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /simple-distributed-sessions-manager/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.github.loafer 6 | simple-distributed-sessions-manager 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | simple-distributed-sessions-manager 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | 19 | javax.servlet 20 | javax.servlet-api 21 | 3.1.0 22 | provided 23 | 24 | 25 | 26 | org.slf4j 27 | slf4j-simple 28 | 1.7.5 29 | 30 | 31 | 32 | redis.clients 33 | jedis 34 | 2.6.0 35 | 36 | 37 | 38 | junit 39 | junit 40 | 4.11 41 | test 42 | 43 | 44 | 45 | 46 | 47 | 48 | org.apache.maven.plugins 49 | maven-compiler-plugin 50 | 3.2 51 | 52 | 1.6 53 | 1.6 54 | utf-8 55 | 56 | 57 | 58 | 59 | org.apache.maven.plugins 60 | maven-source-plugin 61 | 2.4 62 | 63 | 64 | package 65 | 66 | jar-no-fork 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /servlet3.x-session/src/main/java/com/github/loafer/session/support/DefaultSessionIdManager.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.session.support; 2 | 3 | import com.github.loafer.session.SessionIdManager; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import javax.servlet.http.HttpServletRequest; 8 | import java.security.SecureRandom; 9 | import java.util.Random; 10 | 11 | /** 12 | * @author zhaojh 13 | */ 14 | public class DefaultSessionIdManager implements SessionIdManager { 15 | private static final Logger logger = LoggerFactory.getLogger(DefaultSessionIdManager.class); 16 | 17 | // private final static String __NEW_SESSION_ID = "com.github.loafer.newSessionId"; 18 | private Random random; 19 | private boolean weakRandom; 20 | private long reseed=100000L; 21 | 22 | @Override 23 | public void start() { 24 | try{ 25 | random = new SecureRandom(); 26 | }catch (Exception e){ 27 | logger.warn("Could not generate SecureRandom for httpsession-id randomness", e); 28 | random = new Random(); 29 | weakRandom = true; 30 | } 31 | } 32 | 33 | @Override 34 | public void stop() { 35 | 36 | } 37 | 38 | @Override 39 | public String newSessionId(HttpServletRequest request, long created) { 40 | if(request == null){ 41 | return newSessionId(created); 42 | } 43 | 44 | return newSessionId(request.hashCode()); 45 | } 46 | 47 | private String newSessionId(long seedTerm){ 48 | String id = null; 49 | while (id == null || id.length() == 0){ 50 | long r0 = weakRandom ? (hashCode() ^ Runtime.getRuntime().freeMemory() ^ random.nextInt() ^ (seedTerm<<32)) 51 | : random.nextLong(); 52 | 53 | if(r0 < 0) r0 = -r0; 54 | 55 | if (reseed>0 && (r0 % reseed)== 1L){ 56 | logger.info("Reseeding {}", this); 57 | 58 | if(random instanceof SecureRandom){ 59 | SecureRandom secure = (SecureRandom) random; 60 | secure.setSeed(secure.generateSeed(8)); 61 | }else{ 62 | random.setSeed(random.nextLong() ^ System.currentTimeMillis() ^ seedTerm ^ Runtime.getRuntime().freeMemory()); 63 | } 64 | } 65 | 66 | long r1 = weakRandom ? 67 | (hashCode() ^ Runtime.getRuntime().freeMemory() ^ random.nextInt() ^ (seedTerm<<32)) 68 | : random.nextLong(); 69 | 70 | if(r1 < 0) r1 = -r1; 71 | 72 | id = Long.toString(r0, 36) + Long.toString(r1, 36); 73 | } 74 | 75 | logger.info("new httpsession id: {}", id); 76 | return id + ".quick4j"; 77 | } 78 | 79 | public static void main(String[] args){ 80 | final DefaultSessionIdManager manager = new DefaultSessionIdManager(); 81 | manager.start(); 82 | 83 | for(int i=0; i<10; i++){ 84 | Runnable t = new Runnable() { 85 | @Override 86 | public void run() { 87 | String id = manager.newSessionId(this.hashCode()); 88 | logger.info("id: {}, length: {}", id, id.length()); 89 | } 90 | }; 91 | 92 | t.run(); 93 | } 94 | 95 | manager.stop(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /servlet3.x-session/src/main/java/com/github/loafer/session/support/SessionManagerImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.session.support; 2 | 3 | import com.github.loafer.helper.CookieHelper; 4 | import com.github.loafer.session.SessionIdManager; 5 | import com.github.loafer.session.SessionManager; 6 | import com.github.loafer.session.SessionStore; 7 | import com.github.loafer.session.metadata.SessionMetaData; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import javax.servlet.ServletContext; 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.servlet.http.HttpServletResponse; 14 | import javax.servlet.http.HttpSession; 15 | 16 | /** 17 | * @author zhaojh 18 | */ 19 | public class SessionManagerImpl implements SessionManager { 20 | private final Logger logger = LoggerFactory.getLogger(SessionManagerImpl.class); 21 | 22 | private SessionIdManager sessionIdManager; 23 | private SessionStore sessionStore; 24 | private int maxInactiveInterval = 30; 25 | private ServletContext servletContext; 26 | 27 | public SessionManagerImpl(ServletContext servletContext) { 28 | this.servletContext = servletContext; 29 | } 30 | 31 | @Override 32 | public void start() { 33 | sessionIdManager = new DefaultSessionIdManager(); 34 | sessionStore = new RedisSessionStore(); 35 | sessionIdManager.start(); 36 | sessionStore.start(); 37 | } 38 | 39 | @Override 40 | public void stop() { 41 | sessionIdManager.stop(); 42 | sessionStore.stop(); 43 | } 44 | 45 | @Override 46 | public void setMaxInactiveInterval(int interval) { 47 | this.maxInactiveInterval = interval; 48 | } 49 | 50 | @Override 51 | public ServletContext getServletContext() { 52 | return servletContext; 53 | } 54 | 55 | @Override 56 | public void add(HttpSession session) { 57 | sessionStore.putSessionMetaData(session); 58 | } 59 | 60 | @Override 61 | public void remove(HttpSession session) { 62 | sessionStore.removeSessionMetaData(session.getId()); 63 | } 64 | 65 | @Override 66 | public HttpSession newHttpSession(HttpServletRequest request, HttpServletResponse response) { 67 | String id = newSessionId(request); 68 | HttpSession httpSession = new RedisHttpSession(id, maxInactiveInterval, this); 69 | CookieHelper.writeSessionIdToCookie(httpSession.getId(), request, response); 70 | return httpSession; 71 | } 72 | 73 | @Override 74 | public HttpSession getHttpSession(String id) { 75 | SessionMetaData metaData = sessionStore.getSessionMetaData(id); 76 | if(null != metaData){ 77 | return new RedisHttpSession( 78 | id, 79 | metaData.getCreationTime(), 80 | metaData.getLastAccessedTime(), 81 | metaData.getMaxInactiveInterval(), 82 | this 83 | ); 84 | } 85 | 86 | return null; 87 | } 88 | 89 | @Override 90 | public String getRequestedSessionId(HttpServletRequest request) { 91 | String sessionid = request.getParameter(DISTRIBUTED_SESSION_ID); 92 | if(null == sessionid){ 93 | sessionid = CookieHelper.findSessionId(request); 94 | } 95 | return sessionid; 96 | } 97 | 98 | @Override 99 | public SessionStore getSessionStore() { 100 | return sessionStore; 101 | } 102 | 103 | private String newSessionId(HttpServletRequest request) { 104 | return sessionIdManager.newSessionId(request, System.currentTimeMillis()); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /simple-distributed-sessions-manager/src/main/java/com/github/loafer/distributed/httpsession/session/NoStickyHttpSession.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.distributed.httpsession.session; 2 | 3 | import com.github.loafer.distributed.httpsession.SessionManager; 4 | import com.github.loafer.distributed.httpsession.metadata.SessionMetaData; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import javax.servlet.ServletContext; 9 | import javax.servlet.http.HttpSessionBindingEvent; 10 | import javax.servlet.http.HttpSessionBindingListener; 11 | import java.util.Collections; 12 | import java.util.Enumeration; 13 | 14 | /** 15 | * @author zhaojh 16 | */ 17 | public class NoStickyHttpSession extends DistributedHttpSession{ 18 | private static final Logger logger = LoggerFactory.getLogger(NoStickyHttpSession.class); 19 | 20 | public NoStickyHttpSession(String id, 21 | int maxInactiveInterval, 22 | SessionManager sessionManager, 23 | ServletContext servletContext) { 24 | super(id, maxInactiveInterval, sessionManager, servletContext); 25 | } 26 | 27 | public NoStickyHttpSession(String id, 28 | long creationTime, 29 | long lastAccessedTime, 30 | int maxInactiveInterval, 31 | SessionManager sessionManager, 32 | ServletContext servletContext) { 33 | super(id, creationTime, lastAccessedTime, maxInactiveInterval, sessionManager, servletContext); 34 | } 35 | 36 | @Override 37 | public Object getAttribute(String name) { 38 | access(); 39 | return sessionManager.getSessionStorage().getSessionAttribute(getId(), name); 40 | } 41 | 42 | @Override 43 | public Enumeration getAttributeNames() { 44 | access(); 45 | return Collections.enumeration(sessionManager.getSessionStorage().getSessionAttributeNames(getId())); 46 | } 47 | 48 | @Override 49 | public void setAttribute(String name, Object value) { 50 | access(); 51 | 52 | Object oldValue = getAttribute(name); 53 | if(value instanceof HttpSessionBindingListener){ 54 | if(value != oldValue){ 55 | try{ 56 | ((HttpSessionBindingListener)value).valueBound(new HttpSessionBindingEvent(this, name, value)); 57 | }catch (Exception e){ 58 | logger.error("bingEvent error:", e); 59 | throw new RuntimeException(e); 60 | } 61 | } 62 | } 63 | 64 | sessionManager.getSessionStorage().storeSessionAttribute(getId(), name, value); 65 | 66 | if(null != oldValue && oldValue != value && oldValue instanceof HttpSessionBindingListener){ 67 | try{ 68 | ((HttpSessionBindingListener)oldValue).valueUnbound(new HttpSessionBindingEvent(this, name)); 69 | }catch (Exception e){ 70 | logger.error("bingEvent error:", e); 71 | throw new RuntimeException(e); 72 | } 73 | } 74 | } 75 | 76 | @Override 77 | public void removeAttribute(String name) { 78 | access(); 79 | Object oldValue = getAttribute(name); 80 | sessionManager.getSessionStorage().removeSessionAttribute(getId(), name); 81 | if(null != oldValue && oldValue instanceof HttpSessionBindingListener){ 82 | try{ 83 | ((HttpSessionBindingListener)oldValue).valueUnbound(new HttpSessionBindingEvent(this, name)); 84 | }catch (Exception e){ 85 | logger.error("bingEvent error:", e); 86 | throw new RuntimeException(e); 87 | } 88 | } 89 | } 90 | 91 | @Override 92 | protected void reloadAttributes() {} 93 | 94 | @Override 95 | protected void reloadMetaData() { 96 | SessionMetaData metaData = sessionManager.getSessionStorage().getSessionMetaData(getId()); 97 | lastAccessedTime = metaData.getLastAccessedTime(); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /simple-distributed-sessions-manager/src/main/java/com/github/loafer/distributed/httpsession/session/StickyHttpSession.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.distributed.httpsession.session; 2 | 3 | import com.github.loafer.distributed.httpsession.SessionManager; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import javax.servlet.ServletContext; 8 | import javax.servlet.http.HttpSessionBindingEvent; 9 | import javax.servlet.http.HttpSessionBindingListener; 10 | import java.util.Collections; 11 | import java.util.Enumeration; 12 | import java.util.Map; 13 | import java.util.concurrent.ConcurrentHashMap; 14 | 15 | /** 16 | * @author zhaojh 17 | */ 18 | public class StickyHttpSession extends DistributedHttpSession{ 19 | private static final Logger logger = LoggerFactory.getLogger(StickyHttpSession.class); 20 | private final Map attributes = new ConcurrentHashMap(); 21 | 22 | public StickyHttpSession(String id, 23 | int maxInactiveInterval, 24 | SessionManager sessionManager, 25 | ServletContext servletContext) { 26 | super(id, maxInactiveInterval, sessionManager, servletContext); 27 | } 28 | 29 | public StickyHttpSession(String id, 30 | long creationTime, 31 | long lastAccessedTime, 32 | int maxInactiveInterval, 33 | SessionManager sessionManager, 34 | ServletContext servletContext) { 35 | super(id, creationTime, lastAccessedTime, 36 | maxInactiveInterval, sessionManager, servletContext); 37 | } 38 | 39 | @Override 40 | public Object getAttribute(String name) { 41 | access(); 42 | return attributes.get(name); 43 | } 44 | 45 | @Override 46 | public Enumeration getAttributeNames() { 47 | access(); 48 | return Collections.enumeration(attributes.keySet()); 49 | } 50 | 51 | @Override 52 | public void setAttribute(String name, Object value) { 53 | access(); 54 | 55 | Object oldValue = attributes.get(name); 56 | if(oldValue instanceof HttpSessionBindingListener){ 57 | if(value != oldValue){ 58 | try{ 59 | ((HttpSessionBindingListener)value).valueBound(new HttpSessionBindingEvent(this, name, value)); 60 | }catch (Exception e){ 61 | logger.error("bingEvent error:", e); 62 | throw new RuntimeException(e); 63 | } 64 | } 65 | } 66 | 67 | Object unbound = attributes.put(name, value); 68 | sessionManager.getSessionStorage().storeSessionAttribute(getId(), name, value); 69 | 70 | if(null != unbound && unbound != value && unbound instanceof HttpSessionBindingListener){ 71 | try{ 72 | ((HttpSessionBindingListener)unbound).valueUnbound(new HttpSessionBindingEvent(this, name)); 73 | }catch (Exception e){ 74 | logger.error("bingEvent error:", e); 75 | throw new RuntimeException(e); 76 | } 77 | } 78 | } 79 | 80 | @Override 81 | public void removeAttribute(String name) { 82 | access(); 83 | sessionManager.getSessionStorage().removeSessionAttribute(getId(), name); 84 | Object unbound = attributes.remove(name); 85 | if(null != unbound && unbound instanceof HttpSessionBindingListener){ 86 | try{ 87 | ((HttpSessionBindingListener)unbound).valueUnbound(new HttpSessionBindingEvent(this, name)); 88 | }catch (Exception e){ 89 | logger.error("bingEvent error:", e); 90 | throw new RuntimeException(e); 91 | } 92 | } 93 | } 94 | 95 | /** 96 | * 注意:将Session Storage上的内容刷新到本地时, 97 | * 不再触发HttpSessionBindingListener的valueBound和valueUnbound事件。 98 | */ 99 | @Override 100 | protected void reloadAttributes() { 101 | attributes.clear(); 102 | attributes.putAll(sessionManager.getSessionStorage().getSessionAttributes(getId())); 103 | } 104 | 105 | @Override 106 | public void reloadMetaData() { 107 | 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /servlet3.x-session/src/main/java/com/github/loafer/session/support/RedisSessionStore.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.session.support; 2 | 3 | import com.github.loafer.session.SessionStore; 4 | import com.github.loafer.session.metadata.SessionMetaData; 5 | import com.github.loafer.util.SerializationUtils; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import redis.clients.jedis.Jedis; 9 | 10 | import javax.servlet.http.HttpSession; 11 | import java.util.*; 12 | 13 | /** 14 | * @author zhaojh 15 | */ 16 | public class RedisSessionStore implements SessionStore { 17 | private static final Logger logger = LoggerFactory.getLogger(RedisSessionStore.class); 18 | private static final String SESSION_METADATA_KEY = "httpsession:%s:metadata"; 19 | private static final String SESSION_ATTRIBUTE_KEY = "httpsession:%s:attribute"; 20 | private Jedis jedis; 21 | 22 | @Override 23 | public void start() { 24 | jedis = new Jedis("192.168.56.110"); 25 | } 26 | 27 | @Override 28 | public void stop() { 29 | jedis.quit(); 30 | } 31 | 32 | @Override 33 | public void putSessionMetaData(HttpSession session) { 34 | Map sessionAttributes = new HashMap(); 35 | sessionAttributes.put(AbstractDistributedHttpSession.CREATION_TIME_KEY, String.valueOf(session.getCreationTime())); 36 | sessionAttributes.put(AbstractDistributedHttpSession.LAST_ACCESSED_TIME_KEY, String.valueOf(session.getLastAccessedTime())); 37 | sessionAttributes.put(AbstractDistributedHttpSession.MAX_INACTIVE_INTERVAL_KEY, String.valueOf(session.getMaxInactiveInterval())); 38 | 39 | String key = String.format(SESSION_METADATA_KEY, session.getId()); 40 | jedis.hmset(key, sessionAttributes); 41 | } 42 | 43 | @Override 44 | public SessionMetaData getSessionMetaData(String sessionid) { 45 | String key = String.format(SESSION_METADATA_KEY, sessionid); 46 | Map sessionAttributes = jedis.hgetAll(key); 47 | if (null != sessionAttributes && !sessionAttributes.isEmpty()){ 48 | return new SessionMetaData( 49 | sessionid, 50 | Long.parseLong(sessionAttributes.get("CreationTime")), 51 | Long.parseLong(sessionAttributes.get("LastAccessedTime")), 52 | Integer.parseInt(sessionAttributes.get("MaxInactiveInterval")) 53 | ); 54 | } 55 | return null; 56 | } 57 | 58 | @Override 59 | public void removeSessionMetaData(String sessionid) { 60 | String metakey = String.format(SESSION_METADATA_KEY, sessionid); 61 | String attributekey = String.format(SESSION_ATTRIBUTE_KEY, sessionid); 62 | jedis.del(metakey); 63 | jedis.del(attributekey.getBytes()); 64 | } 65 | 66 | @Override 67 | public void updateSessionMetaData(String sessionid, String name, Object value) { 68 | String metakey = String.format(SESSION_METADATA_KEY, sessionid); 69 | jedis.hset(metakey, name, String.valueOf(value)); 70 | } 71 | 72 | @Override 73 | public void setAttribute(String sessionid, String name, Object value) { 74 | String key = String.format(SESSION_ATTRIBUTE_KEY, sessionid); 75 | jedis.hset(key.getBytes(), name.getBytes(), SerializationUtils.serialize(value)); 76 | } 77 | 78 | @Override 79 | public void removeAttribute(String sessionid, String name) { 80 | String key = String.format(SESSION_ATTRIBUTE_KEY, sessionid); 81 | jedis.hdel(key.getBytes(), name.getBytes()); 82 | } 83 | 84 | @Override 85 | public Object getAttribute(String sessionid, String name) { 86 | String key = String.format(SESSION_ATTRIBUTE_KEY, sessionid); 87 | return SerializationUtils.deserialize(jedis.hget(key.getBytes(), name.getBytes())); 88 | } 89 | 90 | @Override 91 | public List getAttributeNames(String sessionid) { 92 | String key = String.format(SESSION_ATTRIBUTE_KEY, sessionid); 93 | Map attributes = jedis.hgetAll(key.getBytes()); 94 | if(!attributes.isEmpty()){ 95 | Iterator iterator = attributes.keySet().iterator(); 96 | List attributeNames = new ArrayList(); 97 | while (iterator.hasNext()){ 98 | attributeNames.add(new String(iterator.next())); 99 | } 100 | 101 | return attributeNames; 102 | } 103 | 104 | return Collections.emptyList(); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /simple-distributed-sessions-manager/src/main/java/com/github/loafer/distributed/httpsession/session/DistributedHttpSession.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.distributed.httpsession.session; 2 | 3 | import com.github.loafer.distributed.httpsession.SessionManager; 4 | import com.github.loafer.distributed.httpsession.metadata.SessionMetaData; 5 | 6 | import javax.servlet.ServletContext; 7 | import javax.servlet.http.HttpSession; 8 | import javax.servlet.http.HttpSessionContext; 9 | import java.util.Collections; 10 | 11 | /** 12 | * @author zhaojh 13 | */ 14 | public abstract class DistributedHttpSession implements HttpSession{ 15 | private String id; 16 | private final long creationTime; 17 | private int maxInactiveInterval; 18 | private boolean newSession; 19 | private boolean persistent; 20 | private boolean validate = true; 21 | private ServletContext servletContext; 22 | 23 | protected SessionManager sessionManager; 24 | protected long lastAccessedTime; 25 | 26 | 27 | 28 | public DistributedHttpSession(String id, 29 | int maxInactiveInterval, 30 | SessionManager sessionManager, 31 | ServletContext servletContext) { 32 | this.id = id; 33 | this.creationTime = System.currentTimeMillis(); 34 | this.lastAccessedTime = this.creationTime; 35 | this.maxInactiveInterval = maxInactiveInterval; 36 | this.sessionManager = sessionManager; 37 | this.newSession = true; 38 | this.persistent = false; 39 | this.servletContext = servletContext; 40 | } 41 | 42 | public DistributedHttpSession(String id, 43 | long creationTime, 44 | long lastAccessedTime, 45 | int maxInactiveInterval, 46 | SessionManager sessionManager, 47 | ServletContext servletContext) { 48 | this.id = id; 49 | this.creationTime = creationTime; 50 | this.lastAccessedTime = lastAccessedTime; 51 | this.maxInactiveInterval = maxInactiveInterval; 52 | this.sessionManager = sessionManager; 53 | this.newSession = false; 54 | this.persistent = true; 55 | this.servletContext = servletContext; 56 | } 57 | 58 | @Override 59 | public long getCreationTime() { 60 | return creationTime; 61 | } 62 | 63 | @Override 64 | public String getId() { 65 | return id; 66 | } 67 | 68 | @Override 69 | public long getLastAccessedTime() { 70 | return lastAccessedTime; 71 | } 72 | 73 | @Override 74 | public ServletContext getServletContext() { 75 | return servletContext; 76 | } 77 | 78 | @Override 79 | public void setMaxInactiveInterval(int interval) { 80 | maxInactiveInterval = interval; 81 | } 82 | 83 | @Override 84 | public int getMaxInactiveInterval() { 85 | return maxInactiveInterval; 86 | } 87 | 88 | @Override 89 | public HttpSessionContext getSessionContext() { 90 | return null; 91 | } 92 | 93 | @Override 94 | public Object getValue(String name) { 95 | return getAttribute(name); 96 | } 97 | 98 | @Override 99 | public String[] getValueNames() { 100 | return Collections.list(getAttributeNames()).toArray(new String[]{}); 101 | } 102 | 103 | @Override 104 | public void putValue(String name, Object value) { 105 | setAttribute(name, value); 106 | } 107 | 108 | @Override 109 | public void removeValue(String name) { 110 | removeAttribute(name); 111 | } 112 | 113 | @Override 114 | public void invalidate() { 115 | sessionManager.removeHttpSession(this); 116 | } 117 | 118 | @Override 119 | public boolean isNew() { 120 | return newSession; 121 | } 122 | 123 | public boolean isValid(){ 124 | if(maxInactiveInterval >0 && (lastAccessedTime + maxInactiveInterval * 1000) < System.currentTimeMillis()){ 125 | validate = false; 126 | } 127 | return validate; 128 | } 129 | 130 | public void refresh(){ 131 | reloadMetaData(); 132 | reloadAttributes(); 133 | } 134 | 135 | protected abstract void reloadAttributes(); 136 | protected abstract void reloadMetaData(); 137 | 138 | protected void access(){ 139 | synchronized (this){ 140 | if(!persistent || !sessionManager.getSessionStorage().isStored(this)){ 141 | sessionManager.getSessionStorage().storeSessionMetaData(this); 142 | persistent = true; 143 | } 144 | 145 | newSession = false; 146 | updateLastAccessedTime(); 147 | } 148 | } 149 | 150 | private void updateLastAccessedTime(){ 151 | lastAccessedTime = System.currentTimeMillis(); 152 | if(persistent){ 153 | sessionManager.getSessionStorage().updateSessionMetaDataField(getId(), SessionMetaData.LAST_ACCESSED_TIME_KEY, lastAccessedTime); 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /simple-distributed-sessions-manager/src/main/java/com/github/loafer/distributed/httpsession/filter/DistributableSessionFilter.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.distributed.httpsession.filter; 2 | 3 | import com.github.loafer.distributed.httpsession.SessionManager; 4 | import com.github.loafer.distributed.httpsession.helper.CookieHelper; 5 | import com.github.loafer.distributed.httpsession.manager.NoStickySessionManager; 6 | import com.github.loafer.distributed.httpsession.manager.StickySessionManager; 7 | import com.github.loafer.distributed.httpsession.session.NoStickyHttpSession; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import javax.servlet.*; 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.servlet.http.HttpServletRequestWrapper; 14 | import javax.servlet.http.HttpServletResponse; 15 | import javax.servlet.http.HttpSession; 16 | import java.io.IOException; 17 | 18 | /** 19 | * @author zhaojh 20 | */ 21 | public class DistributableSessionFilter implements Filter { 22 | private static Logger logger = LoggerFactory.getLogger(DistributableSessionFilter.class); 23 | private SessionManager sessionManager; 24 | private int maxInactiveInterval = 60 * 30; 25 | private String loadBalancingStrategy = "sticky"; 26 | 27 | @Override 28 | public void init(FilterConfig filterConfig) throws ServletException { 29 | String sessionTimeout = filterConfig.getInitParameter("sessionTimeout"); 30 | //默认最大有效期30分钟 31 | try{ 32 | maxInactiveInterval = 60 * Integer.parseInt(sessionTimeout); 33 | }catch (NumberFormatException e){} 34 | 35 | 36 | loadBalancingStrategy = filterConfig.getInitParameter("loadBalancingStrategy"); 37 | if(loadBalancingStrategy.equalsIgnoreCase("sticky")){ 38 | logger.info("应用负载均衡策略为: Sticky Session"); 39 | sessionManager = new StickySessionManager(filterConfig.getServletContext(), maxInactiveInterval); 40 | }else{ 41 | logger.info("应用负载均衡策略为: 非Sticky Session"); 42 | sessionManager = new NoStickySessionManager(filterConfig.getServletContext(), maxInactiveInterval); 43 | } 44 | sessionManager.start(); 45 | } 46 | 47 | @Override 48 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 49 | throws IOException, ServletException { 50 | 51 | final HttpServletRequest httpRequest = (HttpServletRequest) request; 52 | final HttpServletResponse httpReponse = (HttpServletResponse) response; 53 | 54 | HttpServletRequest requestWrapper = new HttpServletRequestWrapper(httpRequest){ 55 | private HttpSession session; 56 | 57 | @Override 58 | public HttpSession getSession(boolean create) { 59 | if(null != session) return session; 60 | 61 | logger.info("============================"); 62 | String sessionid = getRequestedSessionId(); 63 | 64 | if(null == sessionid){ 65 | logger.info("当前request还未与Session关联."); 66 | } 67 | 68 | if(sessionid != null){ 69 | logger.info("当前request与session[{}]关联.", sessionid); 70 | session = sessionManager.getHttpSession(sessionid); 71 | 72 | if(null == session){ 73 | logger.info("session[{}]已失效.", sessionid); 74 | } 75 | 76 | if(sessionManager.isValid(session)){ 77 | logger.info("session[{}]有效。", sessionid); 78 | return session; 79 | }else{ 80 | logger.info("session[{}]已失效。", sessionid); 81 | } 82 | } 83 | 84 | logger.info("create: {}", create); 85 | if(!create){ 86 | logger.info("未要求创建新session. 返回null"); 87 | return null; 88 | } 89 | 90 | session = sessionManager.newHttpSession(this); 91 | logger.info("为当前request创建一个新session[{}].", session.getId()); 92 | CookieHelper.writeSessionIdToCookie(session.getId(), httpRequest, httpReponse); 93 | return session; 94 | } 95 | 96 | @Override 97 | public HttpSession getSession() { 98 | return this.getSession(true); 99 | } 100 | 101 | @Override 102 | public String getRequestedSessionId() { 103 | String sessionid = httpRequest.getParameter(SessionManager.DISTRIBUTED_SESSION_ID); 104 | if(null == sessionid){ 105 | sessionid = CookieHelper.findSessionId(httpRequest); 106 | if(null != sessionid){ 107 | logger.info("客户端Cookie中持有与当前request关联的session[{}]标识.", sessionid); 108 | } 109 | }else{ 110 | logger.info("url中持有与当前request关联的session[{}]标识.", sessionid); 111 | } 112 | return sessionid; 113 | } 114 | }; 115 | 116 | chain.doFilter(requestWrapper, httpReponse); 117 | } 118 | 119 | @Override 120 | public void destroy() { 121 | sessionManager.stop(); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /servlet3.x-session/src/main/java/com/github/loafer/session/support/AbstractDistributedHttpSession.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.session.support; 2 | 3 | import com.github.loafer.session.SessionManager; 4 | import com.github.loafer.session.SessionStore; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import javax.servlet.ServletContext; 9 | import javax.servlet.http.HttpSession; 10 | import javax.servlet.http.HttpSessionContext; 11 | import java.util.Collections; 12 | 13 | /** 14 | * @author zhaojh 15 | */ 16 | public abstract class AbstractDistributedHttpSession implements HttpSession{ 17 | private static final Logger logger = LoggerFactory.getLogger(AbstractDistributedHttpSession.class); 18 | public static final String LAST_ACCESSED_TIME_KEY = "lastAccessedTime"; 19 | public static final String CREATION_TIME_KEY = "creationTime"; 20 | public static final String MAX_INACTIVE_INTERVAL_KEY = "maxInactiveInterval"; 21 | private String id; 22 | private final long creationTm; 23 | private long lastAccessedTm; 24 | private int maxInactiveInterval; 25 | private boolean newSession; 26 | private boolean persistent; 27 | protected SessionManager sessionManager; 28 | protected SessionStore sessionStore; 29 | 30 | /** 31 | * 创建一个新session 32 | * @param id 33 | * @param maxInactiveInterval 34 | * @param sessionManager 35 | */ 36 | public AbstractDistributedHttpSession(String id, 37 | int maxInactiveInterval, 38 | SessionManager sessionManager) { 39 | this.id = id; 40 | this.creationTm = System.currentTimeMillis(); 41 | this.lastAccessedTm = this.creationTm; 42 | this.maxInactiveInterval = maxInactiveInterval; 43 | this.newSession = true; 44 | this.persistent = false; 45 | this.sessionManager = sessionManager; 46 | this.sessionStore = this.sessionManager.getSessionStore(); 47 | } 48 | 49 | /** 50 | * 根据sessionMetaData还原一个已存在的session 51 | * @param id 52 | * @param creationTm 53 | * @param lastAccessedTm 54 | * @param maxInactiveInterval 55 | * @param sessionManager 56 | */ 57 | public AbstractDistributedHttpSession(String id, 58 | long creationTm, 59 | long lastAccessedTm, 60 | int maxInactiveInterval, 61 | SessionManager sessionManager) { 62 | this.id = id; 63 | this.creationTm = creationTm; 64 | this.lastAccessedTm = lastAccessedTm; 65 | this.maxInactiveInterval = maxInactiveInterval; 66 | this.newSession = false; 67 | this.persistent = true; 68 | this.sessionManager = sessionManager; 69 | this.sessionStore = this.sessionManager.getSessionStore(); 70 | } 71 | 72 | // @Override 73 | // public Object getAttribute(String name) { 74 | // return null; 75 | // } 76 | 77 | // @Override 78 | // public Enumeration getAttributeNames() { 79 | // return null; 80 | // } 81 | 82 | @Override 83 | public long getCreationTime() { 84 | return 0; 85 | } 86 | 87 | @Override 88 | public String getId() { 89 | return id; 90 | } 91 | 92 | @Override 93 | public long getLastAccessedTime() { 94 | return lastAccessedTm; 95 | } 96 | 97 | @Override 98 | public int getMaxInactiveInterval() { 99 | return maxInactiveInterval; 100 | } 101 | 102 | @Override 103 | public ServletContext getServletContext() { 104 | return null; 105 | } 106 | 107 | @Override 108 | public HttpSessionContext getSessionContext() { 109 | return null; 110 | } 111 | 112 | @Override 113 | public Object getValue(String name) { 114 | return getAttribute(name); 115 | } 116 | 117 | @Override 118 | public String[] getValueNames() { 119 | return Collections.list(getAttributeNames()).toArray(new String[]{}); 120 | } 121 | 122 | @Override 123 | public void invalidate() { 124 | sessionManager.remove(this); 125 | } 126 | 127 | @Override 128 | public boolean isNew() { 129 | return newSession; 130 | } 131 | 132 | @Override 133 | public void putValue(String name, Object value) { 134 | setAttribute(name, value); 135 | } 136 | 137 | // @Override 138 | // public void removeAttribute(String name) { 139 | // 140 | // } 141 | 142 | @Override 143 | public void removeValue(String name) { 144 | removeAttribute(name); 145 | } 146 | 147 | // @Override 148 | // public void setAttribute(String name, Object value) { 149 | // 150 | // } 151 | 152 | @Override 153 | public void setMaxInactiveInterval(int interval) { 154 | maxInactiveInterval = interval; 155 | } 156 | 157 | public void access(boolean joined){ 158 | if(newSession && joined){ 159 | logger.info("保存[{}]的元数据。", getId()); 160 | sessionManager.add(this); 161 | newSession = false; 162 | persistent = true; 163 | } 164 | updateLastAccessedTime(); 165 | } 166 | 167 | private void updateLastAccessedTime(){ 168 | lastAccessedTm = System.currentTimeMillis(); 169 | if(persistent){ 170 | sessionStore.updateSessionMetaData(getId(), LAST_ACCESSED_TIME_KEY, lastAccessedTm); 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /simple-distributed-sessions-manager/src/main/java/com/github/loafer/distributed/httpsession/storage/RedisSessionStorage.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.distributed.httpsession.storage; 2 | 3 | import com.github.loafer.distributed.httpsession.SessionStorage; 4 | import com.github.loafer.distributed.httpsession.metadata.SessionMetaData; 5 | import com.github.loafer.distributed.httpsession.util.SerializationUtils; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import redis.clients.jedis.Jedis; 9 | 10 | import javax.servlet.http.HttpSession; 11 | import java.util.*; 12 | 13 | /** 14 | * @author zhaojh 15 | */ 16 | public class RedisSessionStorage implements SessionStorage{ 17 | private static final Logger logger = LoggerFactory.getLogger(RedisSessionStorage.class); 18 | private static final String SESSION_METADATA_KEY = "httpsession:%s:metadata"; 19 | private static final String SESSION_ATTRIBUTE_KEY = "httpsession:%s:attribute"; 20 | private Jedis jedis; 21 | 22 | @Override 23 | public void start() { 24 | logger.info("启动Session Storage for redis."); 25 | jedis = new Jedis("192.168.56.110"); 26 | } 27 | 28 | @Override 29 | public void stop() { 30 | jedis.quit(); 31 | } 32 | 33 | @Override 34 | public boolean isStored(HttpSession session) { 35 | String key = String.format(SESSION_METADATA_KEY, session.getId()); 36 | return jedis.exists(key); 37 | } 38 | 39 | @Override 40 | public void storeSessionMetaData(HttpSession session) { 41 | Map sessionAttributes = new HashMap(); 42 | sessionAttributes.put(SessionMetaData.CREATION_TIME_KEY, String.valueOf(session.getCreationTime())); 43 | sessionAttributes.put(SessionMetaData.LAST_ACCESSED_TIME_KEY, String.valueOf(session.getLastAccessedTime())); 44 | sessionAttributes.put(SessionMetaData.MAX_INACTIVE_INTERVAL_KEY, String.valueOf(session.getMaxInactiveInterval())); 45 | 46 | String key = String.format(SESSION_METADATA_KEY, session.getId()); 47 | jedis.hmset(key, sessionAttributes); 48 | } 49 | 50 | @Override 51 | public void removeSession(String sessionid) { 52 | String metakey = String.format(SESSION_METADATA_KEY, sessionid); 53 | String attributekey = String.format(SESSION_ATTRIBUTE_KEY, sessionid); 54 | jedis.del(metakey); 55 | jedis.del(attributekey.getBytes()); 56 | } 57 | 58 | @Override 59 | public SessionMetaData getSessionMetaData(String sessionid) { 60 | String key = String.format(SESSION_METADATA_KEY, sessionid); 61 | Map sessionAttributes = jedis.hgetAll(key); 62 | if (null != sessionAttributes && !sessionAttributes.isEmpty()){ 63 | return new SessionMetaData( 64 | sessionid, 65 | Long.parseLong(sessionAttributes.get(SessionMetaData.CREATION_TIME_KEY)), 66 | Long.parseLong(sessionAttributes.get(SessionMetaData.LAST_ACCESSED_TIME_KEY)), 67 | Integer.parseInt(sessionAttributes.get(SessionMetaData.MAX_INACTIVE_INTERVAL_KEY)) 68 | ); 69 | } 70 | return null; 71 | } 72 | 73 | @Override 74 | public void updateSessionMetaDataField(String sessionid, String name, Object value) { 75 | String key = String.format(SESSION_METADATA_KEY, sessionid); 76 | jedis.hset(key, name, String.valueOf(value)); 77 | } 78 | 79 | @Override 80 | public Object getSessionMetaDataField(String sessionid, String name) { 81 | String key = String.format(SESSION_METADATA_KEY, sessionid); 82 | return jedis.hget(key, name); 83 | } 84 | 85 | @Override 86 | public void storeSessionAttribute(String sessionid, String name, Object value) { 87 | String key = String.format(SESSION_ATTRIBUTE_KEY, sessionid); 88 | jedis.hset(key.getBytes(), name.getBytes(), SerializationUtils.serialize(value)); 89 | } 90 | 91 | @Override 92 | public void removeSessionAttribute(String sessionid, String name) { 93 | String key = String.format(SESSION_ATTRIBUTE_KEY, sessionid); 94 | jedis.hdel(key.getBytes(), name.getBytes()); 95 | } 96 | 97 | @Override 98 | public Object getSessionAttribute(String sessionid, String name) { 99 | String key = String.format(SESSION_ATTRIBUTE_KEY, sessionid); 100 | return SerializationUtils.deserialize(jedis.hget(key.getBytes(), name.getBytes())); 101 | } 102 | 103 | @Override 104 | public List getSessionAttributeNames(String sessionid) { 105 | String key = String.format(SESSION_ATTRIBUTE_KEY, sessionid); 106 | Map attributes = jedis.hgetAll(key.getBytes()); 107 | if(!attributes.isEmpty()){ 108 | Iterator iterator = attributes.keySet().iterator(); 109 | List attributeNames = new ArrayList(); 110 | while (iterator.hasNext()){ 111 | attributeNames.add(new String(iterator.next())); 112 | } 113 | 114 | return attributeNames; 115 | } 116 | 117 | return Collections.emptyList(); 118 | } 119 | 120 | @Override 121 | public Map getSessionAttributes(String sessionid) { 122 | String key = String.format(SESSION_ATTRIBUTE_KEY, sessionid); 123 | Map attributes = jedis.hgetAll(key.getBytes()); 124 | if(!attributes.isEmpty()){ 125 | Map result = new HashMap(); 126 | for (Iterator> iterator = attributes.entrySet().iterator(); iterator.hasNext();){ 127 | Map.Entry entry = iterator.next(); 128 | result.put(new String(entry.getKey()), SerializationUtils.deserialize(entry.getValue())); 129 | } 130 | return result; 131 | } 132 | return Collections.EMPTY_MAP; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /simple-distributed-sessions-manager/src/main/java/com/github/loafer/distributed/httpsession/manager/AbstractSessionManager.java: -------------------------------------------------------------------------------- 1 | package com.github.loafer.distributed.httpsession.manager; 2 | 3 | import com.github.loafer.distributed.httpsession.SessionIDManager; 4 | import com.github.loafer.distributed.httpsession.SessionManager; 5 | import com.github.loafer.distributed.httpsession.SessionStorage; 6 | import com.github.loafer.distributed.httpsession.manager.task.ClearInvalidSessionScheduledTask; 7 | import com.github.loafer.distributed.httpsession.metadata.SessionMetaData; 8 | import com.github.loafer.distributed.httpsession.session.DistributedHttpSession; 9 | import com.github.loafer.distributed.httpsession.session.StickyHttpSession; 10 | import com.github.loafer.distributed.httpsession.storage.RedisSessionStorage; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import javax.servlet.ServletContext; 15 | import javax.servlet.http.HttpServlet; 16 | import javax.servlet.http.HttpServletRequest; 17 | import javax.servlet.http.HttpSession; 18 | import java.util.Map; 19 | import java.util.concurrent.ConcurrentHashMap; 20 | import java.util.concurrent.Executors; 21 | import java.util.concurrent.ScheduledExecutorService; 22 | import java.util.concurrent.TimeUnit; 23 | 24 | /** 25 | * @author zhaojh 26 | */ 27 | public abstract class AbstractSessionManager implements SessionManager { 28 | private final Logger logger = LoggerFactory.getLogger(AbstractSessionManager.class); 29 | 30 | private int maxInactiveInterval; 31 | private ServletContext servletContext; 32 | 33 | private Map localSessionContainer = new ConcurrentHashMap(); 34 | private SessionStorage sessionStorage; 35 | private SessionIDManager sessionIdManager; 36 | private ScheduledExecutorService scheduledExecutorService; 37 | 38 | 39 | public AbstractSessionManager(ServletContext servletContext, int maxInactiveInterval) { 40 | this.servletContext = servletContext; 41 | this.maxInactiveInterval = maxInactiveInterval; 42 | } 43 | 44 | protected abstract HttpSession newHttpSession(String id, int maxInactiveInterval, ServletContext servletContext); 45 | protected abstract HttpSession findHttpSession(String id); 46 | 47 | @Override 48 | public HttpSession newHttpSession(HttpServletRequest request) { 49 | String id = newSessionId(request); 50 | HttpSession session = newHttpSession(id, maxInactiveInterval, servletContext); 51 | addSessionToLocal(session); 52 | return session; 53 | } 54 | 55 | @Override 56 | public HttpSession getHttpSession(String id) { 57 | HttpSession session = findHttpSession(id); 58 | addSessionToLocal(session); 59 | return session; 60 | } 61 | 62 | @Override 63 | public void removeHttpSession(HttpSession session) { 64 | removeSessionFromStorage(session); 65 | removeSessionFromLocal(session); 66 | } 67 | 68 | @Override 69 | public boolean isValid(HttpSession session) { 70 | if(null == session) return false; 71 | 72 | return ((DistributedHttpSession)session).isValid(); 73 | } 74 | 75 | @Override 76 | public void start() { 77 | logger.info("启动Session Manager."); 78 | sessionIdManager = new DefaultSessionIDManager(); 79 | sessionIdManager.start(); 80 | 81 | sessionStorage = new RedisSessionStorage(); 82 | sessionStorage.start(); 83 | 84 | scheduledExecutorService = Executors.newScheduledThreadPool(1); 85 | scheduledExecutorService.scheduleWithFixedDelay( 86 | new ClearInvalidSessionScheduledTask(localSessionContainer), 87 | 10, 10, TimeUnit.SECONDS); 88 | } 89 | 90 | @Override 91 | public void stop() { 92 | scheduledExecutorService.shutdown(); 93 | sessionIdManager.stop(); 94 | sessionStorage.stop(); 95 | } 96 | 97 | @Override 98 | public SessionStorage getSessionStorage() { 99 | return sessionStorage; 100 | } 101 | 102 | protected ServletContext getServletContext(){ 103 | return servletContext; 104 | } 105 | 106 | protected boolean isStaleSession(HttpSession session){ 107 | Object lastAccessedTime = session.getLastAccessedTime(); 108 | if(sessionStorage.isStored(session)){ 109 | lastAccessedTime = sessionStorage.getSessionMetaDataField(session.getId(), SessionMetaData.LAST_ACCESSED_TIME_KEY); 110 | } 111 | return session.getLastAccessedTime() != Long.valueOf(String.valueOf(lastAccessedTime)).longValue(); 112 | } 113 | 114 | protected SessionMetaData getSessionMetaDataFromStorage(String id){ 115 | return sessionStorage.getSessionMetaData(id); 116 | } 117 | 118 | protected HttpSession findSessionFromLocal(String id){ 119 | HttpSession session = localSessionContainer.get(id); 120 | if(null != session){ 121 | logger.info("本地持有session[{}]的信息.", id); 122 | logger.debug("检查是否需要刷新session."); 123 | if(isStaleSession(session)){ 124 | logger.debug("更新本地session内容与Session Storage中内容一致."); 125 | ((DistributedHttpSession)session).refresh(); 126 | }else{ 127 | logger.debug("无需刷新."); 128 | } 129 | } 130 | return session; 131 | } 132 | 133 | private String newSessionId(HttpServletRequest request){ 134 | return sessionIdManager.newSessionId(request, System.currentTimeMillis()); 135 | } 136 | 137 | private void addSessionToLocal(HttpSession session){ 138 | if (null == session) return; 139 | localSessionContainer.put(session.getId(), session); 140 | } 141 | 142 | private void removeSessionFromLocal(HttpSession session){ 143 | localSessionContainer.remove(session.getId()); 144 | } 145 | 146 | private void removeSessionFromStorage(HttpSession session){ 147 | sessionStorage.removeSession(session.getId()); 148 | } 149 | } 150 | --------------------------------------------------------------------------------