├── .gitignore
├── src
├── test
│ └── resources
│ │ ├── log4j.properties
│ │ ├── applicationContext.xml
│ │ ├── applicationContext1.xml
│ │ └── applicationContext2.xml
└── main
│ └── java
│ └── cn
│ └── uncode
│ └── session
│ ├── SessionListener.java
│ ├── data
│ ├── SessionCache.java
│ ├── SerializeUtil.java
│ ├── SessionCacheManager.java
│ ├── redis
│ │ ├── RedisSessionCache.java
│ │ └── RedisSentinelPool.java
│ ├── memcached
│ │ ├── MemcachedSessionCache.java
│ │ └── MemcachedPool.java
│ └── SessionMap.java
│ ├── SessionSharingFilter.java
│ ├── SessionHttpServletRequestWrapper.java
│ ├── MapSession.java
│ └── HttpSessionWrapper.java
├── README.md
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # except for .gitignore
3 | !.gitignore
4 |
5 | # Ignore working directory #
6 | /target/
7 | .classpath
8 | .project
9 | .settings/
10 | *.iml
11 | .idea/
12 | target/
--------------------------------------------------------------------------------
/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootCategory=INFO, stdout
2 |
3 | log4j.appender.stdout.encoding=UTF-8
4 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
5 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
6 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH\:mm\:ss}\:%p(%L)%t %C - %M - %m%n
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/main/java/cn/uncode/session/SessionListener.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright@xiaocong.tv 2012
3 | */
4 | package cn.uncode.session;
5 |
6 | import javax.servlet.http.HttpSessionEvent;
7 | import javax.servlet.http.HttpSessionListener;
8 |
9 | /**
10 | * @author weijun.ye
11 | * @version
12 | * @date 2012-5-2
13 | */
14 | public class SessionListener implements HttpSessionListener{
15 |
16 | private static final int MAX_INACTIVE_INTERVAL = 1000*60*60*8;
17 |
18 | public void sessionCreated(HttpSessionEvent event) {
19 | //ignore
20 | }
21 |
22 |
23 | public void sessionDestroyed(HttpSessionEvent event) {
24 | //ignore
25 | }
26 |
27 |
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/cn/uncode/session/data/SessionCache.java:
--------------------------------------------------------------------------------
1 | package cn.uncode.session.data;
2 |
3 |
4 |
5 | /**
6 | *
7 | * @author yeweijun
8 | */
9 | public interface SessionCache {
10 |
11 | /**
12 | * 存储session到分布式缓存
13 | * @param sessionId 当前会话id
14 | * @param sessionMap 值对象
15 | * @param timeout 过期时间
16 | */
17 | public void put(String sessionId, SessionMap sessionMap, int timeout);
18 |
19 |
20 | /**
21 | * 从分布式缓存获取会话
22 | * @param sessionId 当前会话id
23 | * @return 会话对象
24 | */
25 | public SessionMap get(String sessionId);
26 |
27 |
28 | /**
29 | * 设置会话有效时间
30 | * @param sessionId 当前会话id
31 | * @param interval 有效时间,单位秒
32 | */
33 | public void setMaxInactiveInterval(String sessionId, int interval);
34 |
35 |
36 | /**
37 | * 销毁当前会话
38 | * @param sessionId 当前会话id
39 | */
40 | public void destroy(String sessionId);
41 |
42 |
43 |
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/cn/uncode/session/data/SerializeUtil.java:
--------------------------------------------------------------------------------
1 | package cn.uncode.session.data;
2 |
3 | import java.io.ByteArrayInputStream;
4 | import java.io.ByteArrayOutputStream;
5 | import java.io.ObjectInputStream;
6 | import java.io.ObjectOutputStream;
7 |
8 | public class SerializeUtil {
9 |
10 | public static byte[] serialize(Object object) {
11 | ObjectOutputStream oos = null;
12 | ByteArrayOutputStream baos = null;
13 | try {
14 | // 序列化
15 | baos = new ByteArrayOutputStream();
16 | oos = new ObjectOutputStream(baos);
17 | oos.writeObject(object);
18 | byte[] bytes = baos.toByteArray();
19 | return bytes;
20 | } catch (Exception e) {
21 | e.printStackTrace();
22 | }
23 | return null;
24 | }
25 |
26 | public static Object unserialize(byte[] bytes) {
27 | ByteArrayInputStream bais = null;
28 | try {
29 | // 反序列化
30 | bais = new ByteArrayInputStream(bytes);
31 | ObjectInputStream ois = new ObjectInputStream(bais);
32 | return ois.readObject();
33 | } catch (Exception e) {
34 |
35 | }
36 | return null;
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/test/resources/applicationContext.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 | 127.0.0.1:11211
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
--------------------------------------------------------------------------------
/src/test/resources/applicationContext1.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
13 |
14 |
22 |
23 |
24 |
25 |
26 |
31 |
32 |
--------------------------------------------------------------------------------
/src/main/java/cn/uncode/session/SessionSharingFilter.java:
--------------------------------------------------------------------------------
1 | package cn.uncode.session;
2 |
3 | import java.io.IOException;
4 |
5 | import javax.servlet.Filter;
6 | import javax.servlet.FilterChain;
7 | import javax.servlet.FilterConfig;
8 | import javax.servlet.ServletContext;
9 | import javax.servlet.ServletException;
10 | import javax.servlet.ServletRequest;
11 | import javax.servlet.ServletResponse;
12 | import javax.servlet.http.HttpServletRequest;
13 |
14 | import org.apache.commons.lang3.StringUtils;
15 |
16 | public class SessionSharingFilter implements Filter {
17 |
18 | private static final int MAX_ACTIVE_TIME = 60*30;//秒
19 | private static final String MAX_ACTIVE_TIME_KEY = "maxActiveTime";
20 |
21 | private ServletContext servletContext;
22 | private int maxActiveTime = MAX_ACTIVE_TIME;
23 |
24 | @Override
25 | public void init(FilterConfig filterConfig) throws ServletException {
26 | servletContext = filterConfig.getServletContext();
27 | String matString = filterConfig.getInitParameter(MAX_ACTIVE_TIME_KEY);
28 | if(StringUtils.isNotEmpty(matString)){
29 | maxActiveTime = Integer.valueOf(matString);
30 | }
31 | }
32 |
33 | @Override
34 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
35 | throws IOException, ServletException {
36 | HttpServletRequest httpServletRequest = (HttpServletRequest)request;
37 | SessionHttpServletRequestWrapper sessionHttpServletRequestWrapper = new SessionHttpServletRequestWrapper(httpServletRequest, maxActiveTime, servletContext);
38 | chain.doFilter(sessionHttpServletRequestWrapper, response);
39 | }
40 |
41 | @Override
42 | public void destroy() {
43 | // TODO Auto-generated method stub
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/cn/uncode/session/data/SessionCacheManager.java:
--------------------------------------------------------------------------------
1 | package cn.uncode.session.data;
2 |
3 | import cn.uncode.session.data.memcached.MemcachedPool;
4 | import cn.uncode.session.data.memcached.MemcachedSessionCache;
5 | import org.apache.commons.lang3.StringUtils;
6 | import org.springframework.beans.BeansException;
7 | import org.springframework.context.ApplicationContext;
8 | import org.springframework.context.ApplicationContextAware;
9 |
10 | import cn.uncode.session.data.redis.RedisSessionCache;
11 |
12 | public class SessionCacheManager implements ApplicationContextAware {
13 |
14 | private static ApplicationContext applicationContext;
15 | private static final SessionCacheManager instance = new SessionCacheManager();
16 |
17 | private SessionCache sessionCache;
18 |
19 | private String beanName;
20 |
21 | public static SessionCache getSessionCache() {
22 | if(instance.sessionCache != null){
23 | return instance.sessionCache;
24 | }else{
25 | if(StringUtils.isNotEmpty(instance.beanName)){
26 | instance.sessionCache = (SessionCache) applicationContext.getBean(instance.beanName);
27 | }else{
28 | if (applicationContext.isTypeMatch("cachePool", MemcachedPool.class)){
29 | instance.sessionCache = new MemcachedSessionCache();
30 | } else {
31 | instance.sessionCache = new RedisSessionCache();
32 | }
33 | }
34 | }
35 | return instance.sessionCache;
36 | }
37 |
38 | @Override
39 | public void setApplicationContext(ApplicationContext applicationContext)
40 | throws BeansException {
41 | SessionCacheManager.applicationContext = applicationContext;
42 | }
43 |
44 | public void setSessionCache(SessionCache sessionCache) {
45 | instance.sessionCache = sessionCache;
46 | }
47 |
48 | public void setBeanName(String beanName) {
49 | instance.beanName = beanName;
50 | }
51 |
52 | public static ApplicationContext getApplicationContext(){
53 | return applicationContext;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/test/resources/applicationContext2.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
13 |
14 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | 0/3 * * * * ?
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/src/main/java/cn/uncode/session/SessionHttpServletRequestWrapper.java:
--------------------------------------------------------------------------------
1 | package cn.uncode.session;
2 |
3 | import javax.servlet.ServletContext;
4 | import javax.servlet.http.Cookie;
5 | import javax.servlet.http.HttpServletRequest;
6 | import javax.servlet.http.HttpServletRequestWrapper;
7 | import javax.servlet.http.HttpSession;
8 |
9 | import cn.uncode.session.data.SessionCacheManager;
10 | import cn.uncode.session.data.SessionMap;
11 |
12 | public class SessionHttpServletRequestWrapper extends HttpServletRequestWrapper {
13 |
14 | public static final String CURRENT_SESSION_ATTR = SessionHttpServletRequestWrapper.class.getName();
15 |
16 |
17 | private ServletContext servletContext;
18 | private int maxActiveTime;
19 |
20 |
21 |
22 | public SessionHttpServletRequestWrapper(HttpServletRequest request, int maxActiveTime, ServletContext servletContext) {
23 | super(request);
24 | this.servletContext = servletContext;
25 | this.maxActiveTime = maxActiveTime;
26 | }
27 |
28 | @Override
29 | public HttpSession getSession() {
30 | return getSession(true);
31 | }
32 |
33 | @Override
34 | public HttpSession getSession(boolean create) {
35 |
36 | HttpSessionWrapper currentSession = getCurrentSession();
37 | if(currentSession != null) {
38 | return currentSession;
39 | }
40 |
41 | String sessionId = null;
42 | Cookie[] cookies = this.getCookies();
43 |
44 | if(cookies != null){
45 | for(Cookie cookie:cookies){
46 | if("JSESSIONID".equals(cookie.getName().toUpperCase())){
47 | sessionId = cookie.getValue();
48 | }
49 | }
50 | }
51 |
52 | if(sessionId != null) {
53 | SessionMap sessionMap = SessionCacheManager.getSessionCache().get(sessionId);
54 | if(sessionMap != null) {
55 | currentSession = new HttpSessionWrapper(sessionMap, SessionCacheManager.getSessionCache(), maxActiveTime, servletContext);
56 | currentSession.setNew(false);
57 | setCurrentSession(currentSession);
58 | return currentSession;
59 | }
60 | }
61 |
62 | if(!create) {
63 | return null;
64 | }
65 |
66 | HttpSession httpSession = super.getSession();
67 | SessionMap sessionMap = new SessionMap(httpSession);
68 | currentSession = new HttpSessionWrapper(sessionMap, SessionCacheManager.getSessionCache(), maxActiveTime, servletContext);
69 | SessionCacheManager.getSessionCache().put(sessionMap.getId(), sessionMap, maxActiveTime);
70 | setCurrentSession(currentSession);
71 | return currentSession;
72 | }
73 |
74 | private HttpSessionWrapper getCurrentSession() {
75 | return (HttpSessionWrapper) getAttribute(CURRENT_SESSION_ATTR);
76 | }
77 |
78 | private void setCurrentSession(HttpSessionWrapper currentSession) {
79 | if(currentSession == null) {
80 | removeAttribute(CURRENT_SESSION_ATTR);
81 | } else {
82 | setAttribute(CURRENT_SESSION_ATTR, currentSession);
83 | }
84 | }
85 |
86 |
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/cn/uncode/session/data/redis/RedisSessionCache.java:
--------------------------------------------------------------------------------
1 | package cn.uncode.session.data.redis;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import cn.uncode.session.data.SerializeUtil;
7 | import cn.uncode.session.data.SessionCache;
8 | import cn.uncode.session.data.SessionMap;
9 | import redis.clients.jedis.Jedis;
10 |
11 | public class RedisSessionCache implements SessionCache{
12 |
13 | private static final Logger LOG =LoggerFactory.getLogger(RedisSessionCache.class);
14 |
15 | @Override
16 | public void put(String sessionId, SessionMap sessionMap, int timeout) {
17 | RedisSentinelPool jedisPool = null;
18 | Jedis jedis = null;
19 | try {
20 | jedisPool = RedisSentinelPool.getPool();
21 | jedis = jedisPool.getResource();
22 | jedis.set(sessionId.getBytes(), SerializeUtil.serialize(sessionMap));
23 | jedis.expire(sessionId, timeout);
24 | } catch (Exception e) {
25 | LOG.error("Put session to redis error", e);
26 | } finally {
27 | jedisPool.returnResource(jedis);
28 | }
29 | }
30 |
31 | @Override
32 | public SessionMap get(String sessionId) {
33 | RedisSentinelPool jedisPool = null;
34 | Jedis jedis = null;
35 | SessionMap sessionMap = null;
36 | byte[] reslut = null;
37 | try {
38 | jedisPool = RedisSentinelPool.getPool();
39 | jedis = jedisPool.getResource();
40 | if (jedis.exists(sessionId)) {
41 | reslut = jedis.get(sessionId.getBytes());
42 | sessionMap = (SessionMap) SerializeUtil.unserialize(reslut);
43 | }
44 | } catch (Exception e) {
45 | LOG.error("Read session from redis error", e);
46 | return null;
47 | } finally {
48 | jedisPool.returnResource(jedis);
49 | }
50 | return sessionMap;
51 | }
52 |
53 | @Override
54 | public void setMaxInactiveInterval(String sessionId, int interval) {
55 | RedisSentinelPool jedisPool = null;
56 | Jedis jedis = null;
57 | try {
58 | jedisPool = RedisSentinelPool.getPool();
59 | jedis = jedisPool.getResource();
60 | if (jedis.exists(sessionId)) {
61 | jedis.expire(sessionId, interval);
62 | }
63 | } catch (Exception e) {
64 | LOG.error("Set session max inactive interval to redis error", e);
65 | } finally {
66 | jedisPool.returnResource(jedis);
67 | }
68 | }
69 |
70 | @Override
71 | public void destroy(String sessionId) {
72 | RedisSentinelPool jedisPool = null;
73 | Jedis jedis = null;
74 | try {
75 | jedisPool = RedisSentinelPool.getPool();
76 | jedis = jedisPool.getResource();
77 | if (jedis.exists(sessionId)) {
78 | jedis.expire(sessionId, 0);
79 | }
80 | } catch (Exception e) {
81 | LOG.error("Destroy session from redis error", e);
82 | } finally {
83 | jedisPool.returnResource(jedis);
84 | }
85 |
86 | }
87 |
88 |
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/java/cn/uncode/session/data/memcached/MemcachedSessionCache.java:
--------------------------------------------------------------------------------
1 | package cn.uncode.session.data.memcached;
2 |
3 | import cn.uncode.session.data.SerializeUtil;
4 | import cn.uncode.session.data.SessionCache;
5 | import cn.uncode.session.data.SessionMap;
6 | import com.whalin.MemCached.MemCachedClient;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import java.util.Date;
11 |
12 | /**
13 | * User: Antergone
14 | * Date: 16/2/25
15 | */
16 | public class MemcachedSessionCache implements SessionCache {
17 |
18 | private static final Logger LOG = LoggerFactory.getLogger(MemcachedSessionCache.class);
19 |
20 | @Override
21 | public void put(String sessionId, SessionMap sessionMap, int timeout) {
22 | MemcachedPool memcachedPool = null;
23 | MemCachedClient memCachedClient = null;
24 | try {
25 | memcachedPool = MemcachedPool.getPool();
26 | memCachedClient = memcachedPool.getClient();
27 | memCachedClient.set(sessionId, SerializeUtil.serialize(sessionMap), new Date(timeout * 1000));
28 | } catch (Exception e) {
29 | LOG.error("Put session to memcached error", e);
30 | }
31 | }
32 |
33 | @Override
34 | public SessionMap get(String sessionId) {
35 | MemcachedPool memcachedPool = null;
36 | MemCachedClient memCachedClient = null;
37 | SessionMap sessionMap = null;
38 | try {
39 | memcachedPool = MemcachedPool.getPool();
40 | memCachedClient = memcachedPool.getClient();
41 | if (memCachedClient.keyExists(sessionId)) {
42 | sessionMap = (SessionMap) memCachedClient.get(sessionId);
43 | }
44 | } catch (Exception e) {
45 | LOG.error("Read session from memcached error", e);
46 | return null;
47 | }
48 | return sessionMap;
49 | }
50 |
51 | @Override
52 | public void setMaxInactiveInterval(String sessionId, int interval) {
53 |
54 | MemcachedPool memcachedPool = null;
55 | MemCachedClient memCachedClient = null;
56 | try {
57 | memcachedPool = MemcachedPool.getPool();
58 | memCachedClient = memcachedPool.getClient();
59 | if (memCachedClient.keyExists(sessionId)) {
60 | memCachedClient.set(sessionId, memCachedClient.get(sessionId), new Date(interval * 1000));
61 | }
62 | } catch (Exception e) {
63 | LOG.error("Set session max inactive interval to memcached error", e);
64 | }
65 |
66 | }
67 |
68 | @Override
69 | public void destroy(String sessionId) {
70 |
71 | MemcachedPool memcachedPool = null;
72 | MemCachedClient memCachedClient = null;
73 | try {
74 | memcachedPool = MemcachedPool.getPool();
75 | memCachedClient = memcachedPool.getClient();
76 | memCachedClient.delete(sessionId);
77 | } catch (Exception e) {
78 | LOG.error("Destroy session from memcached error", e);
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #uncode-session
2 |
3 |
4 | 非常小巧的集群session共享组件,代码千行以内,避免使用应用容器插件的多种烦恼。
5 |
6 |
7 |
8 | # 功能概述
9 |
10 | 1. 非常小巧的集群session公享组件,类似于spring-session。
11 | 2. 总代码不超过1000行。
12 | 3. 易于使用和扩展。
13 |
14 |
15 |
16 |
17 | ------------------------------------------------------------------------
18 |
19 | # 配置
20 |
21 | ## 1. web.xml
22 |
23 |
24 |
25 | SessionSharingFilter
26 | cn.uncode.session.SessionSharingFilter
27 |
28 |
29 | SessionSharingFilter
30 | /*
31 |
32 |
33 | ## 2. 基于Redis的Spring配置
34 |
35 |
36 |
37 | <<<<<<< HEAD
38 |
39 |
40 | =======
41 |
42 | >>>>>>> 58c22ae632334d37423c07f378e242ffea23648e
43 |
44 |
45 | 127.0.0.1:26379
46 | 127.0.0.2:26379
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | ## 3. 基于Memcached的Spring配置
57 |
58 |
59 |
60 |
61 | 127.0.0.1:11211
62 |
63 |
64 |
65 | ------------------------------------------------------------------------
66 |
67 | # 自定义扩展
68 |
69 |
70 | ## 1. 自定义实现类
71 |
72 | public class CustomSessionCache implements SessionCache{
73 |
74 | @Override
75 | public void put(String sessionId, SessionMap sessionMap, int timeout) {
76 |
77 | }
78 |
79 | @Override
80 | public SessionMap get(String sessionId) {
81 |
82 | }
83 |
84 | @Override
85 | public void setMaxInactiveInterval(String sessionId, int interval) {
86 |
87 | }
88 |
89 | @Override
90 | public void destroy(String sessionId) {
91 |
92 | }
93 | }
94 |
95 |
96 | ## 2. 配置管理器
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
109 |
110 |
111 | ------------------------------------------------------------------------
112 |
113 |
114 | # 版权
115 |
116 | 作者:冶卫军(ywj_316@qq.com)
117 | 贡献开发:马煜
118 |
119 | 技术支持QQ群:47306892
120 |
121 | Copyright 2016 www.uncode.cn
122 |
--------------------------------------------------------------------------------
/src/main/java/cn/uncode/session/MapSession.java:
--------------------------------------------------------------------------------
1 | package cn.uncode.session;
2 |
3 | import java.io.Serializable;
4 | import java.util.Enumeration;
5 | import java.util.HashMap;
6 | import java.util.Map;
7 | import java.util.Set;
8 | import java.util.UUID;
9 | import java.util.concurrent.TimeUnit;
10 |
11 | import javax.servlet.http.HttpSession;
12 |
13 | import org.apache.commons.lang3.StringUtils;
14 |
15 | public class MapSession implements Serializable {
16 |
17 | private static final long serialVersionUID = 3455295045889076281L;
18 |
19 | private String id = UUID.randomUUID().toString();
20 | private Map sessionAttrs = new HashMap();
21 | private long creationTime = System.currentTimeMillis();
22 | private long lastAccessedTime = creationTime;
23 | private int maxInactiveInterval;
24 |
25 |
26 | public MapSession(HttpSession session) {
27 | if(session == null) {
28 | throw new IllegalArgumentException("session cannot be null");
29 | }
30 | this.id = session.getId();
31 | this.sessionAttrs = new HashMap();
32 | Enumeration> names = session.getAttributeNames();
33 | while (names.hasMoreElements()) {
34 | String name = (String) names.nextElement();
35 | Object attrValue = session.getAttribute(name);
36 | if(StringUtils.isNotEmpty(name) && attrValue != null){
37 | this.sessionAttrs.put(name, attrValue);
38 | }
39 | }
40 | this.lastAccessedTime = session.getLastAccessedTime();
41 | this.creationTime = session.getCreationTime();
42 | this.maxInactiveInterval = session.getMaxInactiveInterval();
43 | }
44 |
45 |
46 | public String getId() {
47 | return id;
48 | }
49 |
50 | public Map getSessionAttrs() {
51 | return sessionAttrs;
52 | }
53 |
54 | public long getCreationTime() {
55 | return creationTime;
56 | }
57 |
58 | public long getLastAccessedTime() {
59 | return lastAccessedTime;
60 | }
61 |
62 | public int getMaxInactiveInterval() {
63 | return maxInactiveInterval;
64 | }
65 |
66 | public boolean isExpired() {
67 | return isExpired(System.currentTimeMillis());
68 | }
69 |
70 | boolean isExpired(long now) {
71 | if(maxInactiveInterval < 0) {
72 | return false;
73 | }
74 | return now - TimeUnit.SECONDS.toMillis(maxInactiveInterval) >= lastAccessedTime;
75 | }
76 |
77 | public boolean equals(Object obj) {
78 | return obj instanceof MapSession && id.equals(((MapSession) obj).getId());
79 | }
80 |
81 | public int hashCode() {
82 | return id.hashCode();
83 | }
84 |
85 | public Object getAttribute(String attributeName) {
86 | return sessionAttrs.get(attributeName);
87 | }
88 |
89 | public Set getAttributeNames() {
90 | return sessionAttrs.keySet();
91 | }
92 |
93 | public void setAttribute(String attributeName, Object attributeValue) {
94 | sessionAttrs.put(attributeName, attributeValue);
95 |
96 | }
97 |
98 | public void removeAttribute(String attributeName) {
99 | sessionAttrs.remove(attributeName);
100 | }
101 |
102 | public void setMaxInactiveInterval(int interval) {
103 | this.maxInactiveInterval = interval;
104 | }
105 |
106 | public void setId(String id) {
107 | this.id = id;
108 | }
109 |
110 |
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/src/main/java/cn/uncode/session/data/SessionMap.java:
--------------------------------------------------------------------------------
1 | package cn.uncode.session.data;
2 |
3 | import java.io.Serializable;
4 | import java.util.Enumeration;
5 | import java.util.HashMap;
6 | import java.util.Map;
7 | import java.util.Set;
8 | import java.util.UUID;
9 | import java.util.concurrent.TimeUnit;
10 |
11 | import javax.servlet.http.HttpSession;
12 |
13 | import org.apache.commons.lang3.StringUtils;
14 |
15 | public class SessionMap implements Serializable {
16 |
17 | private static final long serialVersionUID = 3455295045889076281L;
18 |
19 | private String id = UUID.randomUUID().toString();
20 | private Map sessionAttrs = new HashMap();
21 | private long creationTime = System.currentTimeMillis();
22 | private long lastAccessedTime = creationTime;
23 | private int maxInactiveInterval;
24 |
25 |
26 | public SessionMap(HttpSession session) {
27 | if(session == null) {
28 | throw new IllegalArgumentException("session cannot be null");
29 | }
30 | this.id = session.getId();
31 | this.sessionAttrs = new HashMap();
32 | Enumeration> names = session.getAttributeNames();
33 | while (names.hasMoreElements()) {
34 | String name = (String) names.nextElement();
35 | Object attrValue = session.getAttribute(name);
36 | if(StringUtils.isNotEmpty(name) && attrValue != null){
37 | this.sessionAttrs.put(name, attrValue);
38 | }
39 | }
40 | this.lastAccessedTime = session.getLastAccessedTime();
41 | this.creationTime = session.getCreationTime();
42 | this.maxInactiveInterval = session.getMaxInactiveInterval();
43 | }
44 |
45 |
46 | public String getId() {
47 | return id;
48 | }
49 |
50 | public Map getSessionAttrs() {
51 | return sessionAttrs;
52 | }
53 |
54 | public long getCreationTime() {
55 | return creationTime;
56 | }
57 |
58 | public long getLastAccessedTime() {
59 | return lastAccessedTime;
60 | }
61 |
62 | public int getMaxInactiveInterval() {
63 | return maxInactiveInterval;
64 | }
65 |
66 | public boolean isExpired() {
67 | return isExpired(System.currentTimeMillis());
68 | }
69 |
70 | boolean isExpired(long now) {
71 | if(maxInactiveInterval < 0) {
72 | return false;
73 | }
74 | return now - TimeUnit.SECONDS.toMillis(maxInactiveInterval) >= lastAccessedTime;
75 | }
76 |
77 | public boolean equals(Object obj) {
78 | return obj instanceof SessionMap && id.equals(((SessionMap) obj).getId());
79 | }
80 |
81 | public int hashCode() {
82 | return id.hashCode();
83 | }
84 |
85 | public Object getAttribute(String attributeName) {
86 | return sessionAttrs.get(attributeName);
87 | }
88 |
89 | public Set getAttributeNames() {
90 | return sessionAttrs.keySet();
91 | }
92 |
93 | public void setAttribute(String attributeName, Object attributeValue) {
94 | sessionAttrs.put(attributeName, attributeValue);
95 |
96 | }
97 |
98 | public void removeAttribute(String attributeName) {
99 | sessionAttrs.remove(attributeName);
100 | }
101 |
102 | public void setMaxInactiveInterval(int interval) {
103 | this.maxInactiveInterval = interval;
104 | }
105 |
106 | public void setId(String id) {
107 | this.id = id;
108 | }
109 |
110 |
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/src/main/java/cn/uncode/session/data/redis/RedisSentinelPool.java:
--------------------------------------------------------------------------------
1 | package cn.uncode.session.data.redis;
2 |
3 | import java.util.HashSet;
4 | import java.util.List;
5 | import java.util.Set;
6 |
7 | import org.apache.commons.lang3.StringUtils;
8 | import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
9 | import org.springframework.beans.factory.DisposableBean;
10 | import org.springframework.beans.factory.InitializingBean;
11 |
12 | import cn.uncode.session.data.SessionCacheManager;
13 | import redis.clients.jedis.Jedis;
14 | import redis.clients.jedis.JedisSentinelPool;
15 |
16 | public class RedisSentinelPool implements InitializingBean,DisposableBean{
17 |
18 | private JedisSentinelPool jedisSentinelPool;
19 |
20 | private List hosts;
21 | private String auth;
22 | private int maxIdle = 5;
23 | private int maxTotal = 20;
24 | private int maxWaitMillis = 10000;
25 | private boolean testOnBorrow = true;
26 | private String name = "redis_master";
27 |
28 | public static RedisSentinelPool getPool(){
29 | return (RedisSentinelPool) SessionCacheManager.getApplicationContext().getBean(RedisSentinelPool.class);
30 | }
31 |
32 | public void setHosts(List hosts) {
33 | this.hosts = hosts;
34 | }
35 |
36 | public void setAuth(String auth) {
37 | this.auth = auth;
38 | }
39 |
40 | public void setName(String name) {
41 | if(StringUtils.isNotEmpty(name)){
42 | this.name = name;
43 | }
44 | }
45 |
46 | public void setMaxIdle(int maxIdle) {
47 | this.maxIdle = maxIdle;
48 | }
49 |
50 | public void setMaxTotal(int maxTotal) {
51 | this.maxTotal = maxTotal;
52 | }
53 |
54 | public void setMaxWaitMillis(int maxWaitMillis) {
55 | this.maxWaitMillis = maxWaitMillis;
56 | }
57 |
58 | public void setTestOnBorrow(boolean testOnBorrow) {
59 | this.testOnBorrow = testOnBorrow;
60 | }
61 |
62 | public Jedis getResource() {
63 | if (jedisSentinelPool != null)
64 | return jedisSentinelPool.getResource();
65 | return null;
66 | }
67 |
68 | public void returnResource(final Jedis jedis) {
69 | if (jedis != null) {
70 | if(jedisSentinelPool !=null)
71 | jedisSentinelPool.returnResource(jedis);
72 | }
73 | }
74 |
75 | public String getCurrentHostMaster(){
76 | if(jedisSentinelPool !=null){
77 | return jedisSentinelPool.getCurrentHostMaster().toString();
78 | }
79 | return "";
80 | }
81 |
82 | @Override
83 | public void destroy() throws Exception {
84 | if(jedisSentinelPool != null){
85 | jedisSentinelPool.close();
86 | }
87 | }
88 |
89 | @Override
90 | public void afterPropertiesSet() throws Exception {
91 | Set set = new HashSet();
92 | if(null != hosts){
93 | for(String host:hosts){
94 | set.add(host);
95 | }
96 | GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
97 | poolConfig.setMaxIdle(maxIdle);
98 | poolConfig.setMaxTotal(maxTotal);
99 | poolConfig.setMaxWaitMillis(maxWaitMillis);
100 | poolConfig.setTestOnBorrow(testOnBorrow);
101 | jedisSentinelPool = new JedisSentinelPool(name, set,poolConfig, auth);
102 | }
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/src/main/java/cn/uncode/session/HttpSessionWrapper.java:
--------------------------------------------------------------------------------
1 | package cn.uncode.session;
2 |
3 | import java.util.Collections;
4 | import java.util.Enumeration;
5 | import java.util.Set;
6 |
7 | import javax.servlet.ServletContext;
8 | import javax.servlet.http.HttpSession;
9 | import javax.servlet.http.HttpSessionContext;
10 |
11 | import cn.uncode.session.data.SessionCache;
12 | import cn.uncode.session.data.SessionMap;
13 |
14 | public class HttpSessionWrapper implements HttpSession {
15 |
16 | private final ServletContext servletContext;
17 | private SessionMap sessionMap;
18 | private SessionCache sessionCache;
19 | private boolean invalidated;
20 | private boolean old;
21 | private int maxActiveTime;
22 |
23 |
24 |
25 | public HttpSessionWrapper(SessionMap sessionMap, SessionCache sessionCache, int maxActiveTime, ServletContext servletContext) {
26 | this.sessionMap = sessionMap;
27 | this.sessionCache = sessionCache;
28 | this.maxActiveTime = maxActiveTime;
29 | this.servletContext = servletContext;
30 | }
31 |
32 | public void setMaxInactiveInterval(int interval) {
33 | sessionMap.setMaxInactiveInterval(interval);
34 | sessionCache.setMaxInactiveInterval(sessionMap.getId(), interval);
35 | }
36 |
37 | public void setAttribute(String name, Object value) {
38 | sessionMap.setAttribute(name, value);
39 | sessionCache.put(sessionMap.getId(), sessionMap, maxActiveTime);
40 | }
41 |
42 | public void removeAttribute(String name) {
43 | sessionMap.removeAttribute(name);
44 | sessionCache.put(sessionMap.getId(), sessionMap, maxActiveTime);
45 | }
46 |
47 | public void putValue(String name, Object value) {
48 | setAttribute(name, value);
49 | }
50 |
51 | public void removeValue(String name) {
52 | removeAttribute(name);
53 | }
54 |
55 | public long getCreationTime() {
56 | return sessionMap.getCreationTime();
57 | }
58 |
59 | public String getId() {
60 | return sessionMap.getId();
61 | }
62 |
63 | public long getLastAccessedTime() {
64 | return sessionMap.getLastAccessedTime();
65 | }
66 |
67 | public ServletContext getServletContext() {
68 | return servletContext;
69 | }
70 |
71 |
72 | public int getMaxInactiveInterval() {
73 | return sessionMap.getMaxInactiveInterval();
74 | }
75 |
76 |
77 | public Object getAttribute(String name) {
78 | return sessionMap.getAttribute(name);
79 | }
80 |
81 | public Object getValue(String name) {
82 | return getAttribute(name);
83 | }
84 |
85 | public Enumeration getAttributeNames() {
86 | return Collections.enumeration(sessionMap.getAttributeNames());
87 | }
88 |
89 | public String[] getValueNames() {
90 | Set attrs = sessionMap.getAttributeNames();
91 | return attrs.toArray(new String[0]);
92 | }
93 |
94 | public void invalidate() {
95 | this.invalidated = true;
96 | sessionCache.destroy(sessionMap.getId());
97 | setCurrentSession(null);
98 | }
99 |
100 | public void setNew(boolean isNew) {
101 | this.old = !isNew;
102 | }
103 |
104 | public boolean isNew() {
105 | return !old;
106 | }
107 |
108 | @Override
109 | public HttpSessionContext getSessionContext() {
110 | return null;
111 | }
112 |
113 | private void setCurrentSession(HttpSessionWrapper currentSession) {
114 | if(currentSession == null) {
115 | removeAttribute(SessionHttpServletRequestWrapper.CURRENT_SESSION_ATTR);
116 | } else {
117 | setAttribute(SessionHttpServletRequestWrapper.CURRENT_SESSION_ATTR, currentSession);
118 | }
119 | }
120 |
121 | }
122 |
--------------------------------------------------------------------------------
/src/main/java/cn/uncode/session/data/memcached/MemcachedPool.java:
--------------------------------------------------------------------------------
1 | package cn.uncode.session.data.memcached;
2 |
3 | import cn.uncode.session.data.SessionCacheManager;
4 | import com.whalin.MemCached.MemCachedClient;
5 | import com.whalin.MemCached.SockIOPool;
6 | import org.springframework.beans.factory.DisposableBean;
7 | import org.springframework.beans.factory.InitializingBean;
8 |
9 | /**
10 | * User: Antergone
11 | * Date: 16/2/25
12 | */
13 | public class MemcachedPool implements InitializingBean, DisposableBean {
14 |
15 | private SockIOPool sockIOPool;
16 | private MemCachedClient memCachedClient;
17 |
18 | private String[] hosts;
19 | private Integer[] weights;
20 | private boolean failOver = true;
21 | private int initConn = 5;
22 | private int minConn = 5;
23 | private int maxConn = 200;
24 | private int maxIdle = 30 * 30 * 1000;
25 | private int mainThreadSleep = 30;
26 | private boolean nagle = false;
27 | private boolean aliveCheck = true;
28 | private int socketTO = 30;
29 | private int socketConnectTO = 0;
30 |
31 | public static MemcachedPool getPool() {
32 | return (MemcachedPool) SessionCacheManager.getApplicationContext().getBean(MemcachedPool.class);
33 | }
34 |
35 | public void setHosts(String[] hosts) {
36 | this.hosts = hosts;
37 | }
38 |
39 | public void setWeights(Integer[] weights) {
40 | this.weights = weights;
41 | }
42 |
43 | public void setFailOver(boolean failOver) {
44 | this.failOver = failOver;
45 | }
46 |
47 | public void setInitConn(int initConn) {
48 | this.initConn = initConn;
49 | }
50 |
51 | public void setMinConn(int minConn) {
52 | this.minConn = minConn;
53 | }
54 |
55 | public void setMaxConn(int maxConn) {
56 | this.maxConn = maxConn;
57 | }
58 |
59 | public void setMaxIdle(int maxIdle) {
60 | this.maxIdle = maxIdle;
61 | }
62 |
63 | public void setMainThreadSleep(int mainThreadSleep) {
64 | this.mainThreadSleep = mainThreadSleep;
65 | }
66 |
67 | public void setNagle(boolean nagle) {
68 | this.nagle = nagle;
69 | }
70 |
71 | public void setAliveCheck(boolean aliveCheck) {
72 | this.aliveCheck = aliveCheck;
73 | }
74 |
75 | public void setSocketTO(int socketTO) {
76 | this.socketTO = socketTO;
77 | }
78 |
79 | public void setSocketConnectTO(int socketConnectTO) {
80 | this.socketConnectTO = socketConnectTO;
81 | }
82 |
83 | public MemCachedClient getClient() {
84 | if (memCachedClient != null)
85 | return memCachedClient;
86 | return null;
87 | }
88 |
89 |
90 | @Override
91 | public void destroy() throws Exception {
92 | if (sockIOPool != null) {
93 | sockIOPool.shutDown();
94 | }
95 | }
96 |
97 | @Override
98 | public void afterPropertiesSet() throws Exception {
99 | if (null != hosts) {
100 | this.sockIOPool = SockIOPool.getInstance();
101 | System.out.println("server are" + hosts);
102 | sockIOPool.setServers(hosts);
103 | sockIOPool.setWeights(weights);
104 | sockIOPool.setFailover(failOver);
105 | sockIOPool.setInitConn(initConn);
106 | sockIOPool.setMinConn(minConn);
107 | sockIOPool.setMaxConn(maxConn);
108 | sockIOPool.setMaxIdle(maxIdle);
109 | sockIOPool.setMaintSleep(mainThreadSleep);
110 | sockIOPool.setNagle(nagle);
111 | sockIOPool.setSocketTO(socketTO);
112 | sockIOPool.setAliveCheck(aliveCheck);
113 | sockIOPool.setSocketConnectTO(socketConnectTO);
114 | sockIOPool.initialize();
115 | memCachedClient = new MemCachedClient();
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | cn.uncode
6 | uncode-session
7 | 1.0.0
8 | jar
9 |
10 | uncode-session
11 | Java session sharing components.
12 | http://git.oschina.net/uncode/uncode-session
13 |
14 |
15 |
16 | The Apache Software License, Version 2.0
17 | http://www.apache.org/licenses/LICENSE-2.0.txt
18 |
19 |
20 |
21 |
22 |
23 | yeweijun
24 | ywj_316@qq.com
25 | http://www.uncode.cn
26 | +8
27 |
28 |
29 |
30 |
31 | scm:git:git@git.oschina.net:uncode/uncode-session.git
32 | scm:git:git@git.oschina.net:uncode/uncode-session.git
33 | git@git.oschina.net:uncode/uncode-session.git
34 |
35 |
36 |
37 | true
38 | true
39 | 3.1
40 | 2.3
41 | 2.9.1
42 | 1.5
43 | UTF-8
44 | UTF-8
45 | 1.7
46 | 3.2.0.RELEASE
47 | 2.4.1
48 | 1.2.16
49 | 4.8.1
50 | 5.1.23
51 | 1.6.4
52 | 3.1
53 | 1.9.2
54 | 3.0.4
55 | 1.0.6
56 | 3.2.2
57 | 2.5
58 |
59 | 1.1.1
60 | 3.3.2
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | org.springframework
70 | spring-core
71 | ${spring.version}
72 |
73 |
74 | org.springframework
75 | spring-context
76 | ${spring.version}
77 |
78 |
79 | org.springframework
80 | spring-context-support
81 | ${spring.version}
82 |
83 |
84 | org.springframework
85 | spring-beans
86 | ${spring.version}
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 | javax.servlet
96 | servlet-api
97 | ${servlet.version}
98 | provided
99 |
100 |
101 |
102 |
103 |
104 |
105 | log4j
106 | log4j
107 | ${log4j.version}
108 |
109 |
110 | org.slf4j
111 | slf4j-api
112 | ${slf4j.version}
113 |
114 |
115 | org.slf4j
116 | slf4j-log4j12
117 | ${slf4j.version}
118 |
119 |
120 |
121 |
122 |
123 | redis.clients
124 | jedis
125 | 2.7.3
126 |
127 |
128 |
129 |
130 |
131 | com.whalin
132 | Memcached-Java-Client
133 | 3.0.2
134 |
135 |
136 |
137 |
138 |
139 | org.apache.commons
140 | commons-lang3
141 | ${commons.lang3.version}
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 | junit
150 | junit
151 | ${junit.version}
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 | maven-compiler-plugin
160 |
161 | ${jdk.version}
162 | ${jdk.version}
163 |
164 |
165 |
166 | org.apache.maven.plugins
167 | maven-source-plugin
168 | ${version.source-plugin}
169 |
170 |
171 |
172 | jar-no-fork
173 |
174 |
175 |
176 |
177 | true
178 |
179 |
180 |
181 | org.apache.maven.plugins
182 | maven-javadoc-plugin
183 | ${version.javadoc-plugin}
184 |
185 |
186 | package
187 |
188 | jar
189 |
190 |
191 |
192 |
193 |
194 | http://docs.oracle.com/javase/7/docs/api
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 | release
204 |
205 |
206 |
207 |
208 |
209 | org.apache.maven.plugins
210 | maven-compiler-plugin
211 | ${version.compiler-plugin}
212 |
213 | ${jdk.version}
214 | ${jdk.version}
215 |
216 |
217 |
218 |
219 | org.apache.maven.plugins
220 | maven-source-plugin
221 | ${version.source-plugin}
222 |
223 |
224 | package
225 |
226 | jar-no-fork
227 |
228 |
229 |
230 |
231 |
232 |
233 | org.apache.maven.plugins
234 | maven-javadoc-plugin
235 | ${version.javadoc-plugin}
236 |
237 |
238 | package
239 |
240 | jar
241 |
242 |
243 |
244 |
245 |
246 |
247 | org.apache.maven.plugins
248 | maven-gpg-plugin
249 | ${version.gpg-plugin}
250 |
251 |
252 | sign-artifacts
253 | verify
254 |
255 | sign
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 | uncode
265 | https://oss.sonatype.org/content/repositories/snapshots/
266 |
267 |
268 | uncode
269 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
270 |
271 |
272 |
273 |
274 |
275 |
276 |
--------------------------------------------------------------------------------