package com.liuxinglanyue.session.redis.share; import java.io.IOException; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Session; import org.apache.catalina.session.StandardManager; import org.apache.catalina.session.StandardSession; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.JedisShardInfo; import redis.clients.jedis.PipelineBlock; import redis.clients.jedis.Protocol; import redis.clients.jedis.ShardedJedis; import redis.clients.jedis.ShardedJedisPool; import redis.clients.jedis.TransactionBlock; import redis.clients.jedis.exceptions.JedisConnectionException; public class RedisManager extends StandardManager { private final Log log = LogFactory.getLog(RedisManager.class); // must not be static public static final String TOMCAT_SESSION_PREFIX = "TS:"; protected final static String NAME = RedisManager.class.getSimpleName(); private final static String INFO = NAME + "/1.0"; //分片连接池 static ShardedJedisPool _shardedPool = null; //连接池 static JedisPool _pool = null; //redis配置 protected JedisPoolConfig connectionPoolConfig = new JedisPoolConfig(); boolean debug = false; //参见nginx boolean stickySession = true; protected String serverlist = "127.0.0.1:6379"; // 用逗号(,)分隔的"ip:port,ip:port,ip:port"列表 protected String socketTO = "6000"; protected byte[] NULL_SESSION = "null".getBytes(); @Override public String getInfo() { return INFO; } @Override public String getName() { return NAME; } public RedisManager() { super(); initRedisPoolConfig(); } @Override public Session findSession(String id) throws IOException { Session session = super.findSession(id); if (!this.isStarted()) { return session; } if (session == null && id != null) { // 说明session有可能在另一个节点上 try { boolean idExists = jedisExists(TOMCAT_SESSION_PREFIX + id); if (idExists) { if (this.debug) { log.info("cached found and local not! id=" + id); } RedisSession redisSession = new RedisSession(this); redisSession.setNew(false); redisSession.setValid(true); redisSession.setCreationTime(System.currentTimeMillis()); redisSession.setMaxInactiveInterval(this.maxInactiveInterval); redisSession.setCachedId(id); this.add(redisSession); sessionCounter++; return redisSession; } } catch (Exception ex) { log.error("error:", ex); } } return session; } @Override public Session createSession(String sessionId) { Session session = super.createSession(sessionId); if (!this.isStarted()) { return session; } sessionId = session.getId(); if (this.debug) { log.info("id=" + sessionId); } return session; } /** * 间接被createSession()调用. */ @Override protected StandardSession getNewSession() { return new RedisSession(this); } @Override public void remove(Session session) { if (this.debug) { log.info("id=" + session.getId()); } super.remove(session); if (!this.isStarted()) { return; } try { jedisDel(TOMCAT_SESSION_PREFIX + session.getId()); } catch (Exception ex) { log.error("error:", ex); } } public boolean isStarted() { return (super.getState() == LifecycleState.STARTED); } @Override protected void startInternal() throws LifecycleException { super.startInternal(); synchronized (RedisManager.class) { try { if (_shardedPool == null && _pool == null) { try { String[] servers = serverlist.split(","); java.util.List<JedisShardInfo> shards = new java.util.ArrayList<JedisShardInfo>(servers.length); for (int i = 0; i < servers.length; i++) { String[] hostAndPort = servers[i].split(":"); JedisShardInfo shardInfo = new JedisShardInfo( hostAndPort[0], Integer.parseInt(hostAndPort[1]), Integer.valueOf(socketTO)); if (hostAndPort.length == 3) { shardInfo.setPassword(hostAndPort[2]); } shards.add(shardInfo); } if (shards.size() == 1) { _pool = new JedisPool(connectionPoolConfig, shards.get(0) .getHost(), shards.get(0).getPort(), shards .get(0).getTimeout(), shards.get(0) .getPassword()); log.info("使用:JedisPool"); } else { _shardedPool = new ShardedJedisPool(connectionPoolConfig, shards); log.info("使用:ShardedJedisPool"); } log.info("RedisShards:" + shards.toString()); log.info("初始化RedisManager:" + this.toString()); } catch (Exception ex) { log.error("error:", ex); } } } catch (Exception ex) { log.error("error:", ex); } } } @Override protected void stopInternal() throws LifecycleException { try { synchronized (RedisManager.class) { if (_shardedPool != null) { ShardedJedisPool myPool = _shardedPool; _shardedPool = null; try { myPool.destroy(); log.info("销毁RedisManager:" + this.toString()); } catch (Exception ex) { log.error("error:", ex); } } if (_pool != null) { JedisPool myPool = _pool; _pool = null; try { myPool.destroy(); log.info("销毁RedisManager:" + this.toString()); } catch (Exception ex) { log.error("error:", ex); } } } } finally { super.stopInternal(); } } protected String generateSessionId() { String result = null; do { if (result != null) { duplicates++; } result = sessionIdGenerator.generateSessionId(); } while (sessions.containsKey(result) || jedisExists(result)); return result; } @Override public String toString() { return "RedisManager{" + "stickySession=" + stickySession + ",debug=" + debug + ",serverlist=" + serverlist + ",socketTO=" + socketTO + '}'; } //---------------------------------------- redis operate public Boolean jedisExists(String key) { if (_pool != null) { Jedis jedis = null; try { jedis = _pool.getResource(); return jedis.exists(key); } finally { if (jedis != null) { try { _pool.returnResource(jedis); } catch (Throwable thex) { } } } } else { ShardedJedis jedis = null; try { jedis = _shardedPool.getResource(); return jedis.exists(key); } finally { if (jedis != null) { try { _shardedPool.returnResource(jedis); } catch (Throwable thex) { } } } } } Long jedisExpire(String key, int seconds) { if (_pool != null) { Jedis jedis = null; try { jedis = _pool.getResource(); return jedis.expire(key, seconds); } finally { if (jedis != null) { try { _pool.returnResource(jedis); } catch (Throwable thex) { } } } } else { ShardedJedis jedis = null; try { jedis = _shardedPool.getResource(); return jedis.expire(key, seconds); } finally { if (jedis != null) { try { _shardedPool.returnResource(jedis); } catch (Throwable thex) { } } } } } java.util.List<Object> jedisMulti(String key, TransactionBlock jedisTransaction) { if (_pool != null) { Jedis jedis = null; try { jedis = _pool.getResource(); return jedis.multi(jedisTransaction); } finally { if (jedis != null) { try { _pool.returnResource(jedis); } catch (Throwable thex) { } } } } else { ShardedJedis jedis = null; try { jedis = _shardedPool.getResource(); byte[] bytesKey = key.getBytes(Protocol.CHARSET); Jedis jedisA = jedis.getShard(bytesKey); return jedisA.multi(jedisTransaction); } catch (IOException e) { throw new JedisConnectionException(e); } finally { if (jedis != null) { try { _shardedPool.returnResource(jedis); } catch (Throwable thex) { } } } } } java.util.List<Object> jedisPipelined(String key, PipelineBlock pipelineBlock) { if (_pool != null) { Jedis jedis = null; try { jedis = _pool.getResource(); return jedis.pipelined(pipelineBlock); } finally { if (jedis != null) { try { _pool.returnResource(jedis); } catch (Throwable thex) { } } } } else { ShardedJedis jedis = null; try { jedis = _shardedPool.getResource(); byte[] bytesKey = key.getBytes(Protocol.CHARSET); Jedis jedisA = jedis.getShard(bytesKey); return jedisA.pipelined(pipelineBlock); } catch (IOException e) { throw new JedisConnectionException(e); } finally { if (jedis != null) { try { _shardedPool.returnResource(jedis); } catch (Throwable thex) { } } } } } byte[] jedisHget(String hkey, String field) { if (_pool != null) { Jedis jedis = null; try { jedis = _pool.getResource(); return jedis.hget(hkey.getBytes(Protocol.CHARSET), field.getBytes(Protocol.CHARSET)); } catch (IOException e) { throw new JedisConnectionException(e); } finally { if (jedis != null) { try { _pool.returnResource(jedis); } catch (Throwable thex) { } } } } else { ShardedJedis jedis = null; try { jedis = _shardedPool.getResource(); return jedis.hget(hkey.getBytes(Protocol.CHARSET), field.getBytes(Protocol.CHARSET)); } catch (IOException e) { throw new JedisConnectionException(e); } finally { if (jedis != null) { try { _shardedPool.returnResource(jedis); } catch (Throwable thex) { } } } } } public Long jedisHset(String hkey, String field, byte[] value) { if (_pool != null) { Jedis jedis = null; try { jedis = _pool.getResource(); return jedis.hset(hkey.getBytes(Protocol.CHARSET), field.getBytes(Protocol.CHARSET), value); } catch (IOException e) { throw new JedisConnectionException(e); } finally { if (jedis != null) { try { _pool.returnResource(jedis); } catch (Throwable thex) { } } } } else { ShardedJedis jedis = null; try { jedis = _shardedPool.getResource(); return jedis.hset(hkey.getBytes(Protocol.CHARSET), field.getBytes(Protocol.CHARSET), value); } catch (IOException e) { throw new JedisConnectionException(e); } finally { if (jedis != null) { try { _shardedPool.returnResource(jedis); } catch (Throwable thex) { } } } } } public Long jedisHdel(String hkey, String field) { if (_pool != null) { Jedis jedis = null; try { jedis = _pool.getResource(); return jedis.hdel(hkey, field); } finally { if (jedis != null) { try { _pool.returnResource(jedis); } catch (Throwable thex) { } } } } else { ShardedJedis jedis = null; try { jedis = _shardedPool.getResource(); return jedis.hdel(hkey, field); } finally { if (jedis != null) { try { _shardedPool.returnResource(jedis); } catch (Throwable thex) { } } } } } Long jedisDel(String key) { if (_pool != null) { Jedis jedis = null; try { jedis = _pool.getResource(); return jedis.del(key.getBytes(Protocol.CHARSET)); } catch (IOException e) { throw new JedisConnectionException(e); } finally { if (jedis != null) { try { _pool.returnResource(jedis); } catch (Throwable thex) { } } } } else { ShardedJedis jedis = null; try { jedis = _shardedPool.getResource(); byte[] bytesKey = key.getBytes(Protocol.CHARSET); Jedis jedisA = jedis.getShard(bytesKey); return jedisA.del(bytesKey); } catch (IOException e) { throw new JedisConnectionException(e); } finally { if (jedis != null) { try { _shardedPool.returnResource(jedis); } catch (Throwable thex) { } } } } } //------------------------------------------ redis config private void initRedisPoolConfig() { connectionPoolConfig.setMinIdle(5); connectionPoolConfig.setMaxIdle(100); connectionPoolConfig.setTestOnBorrow(true); connectionPoolConfig.setTestOnReturn(false); connectionPoolConfig.setTestWhileIdle(false); connectionPoolConfig.setMinEvictableIdleTimeMillis(1000L * 60L * 10L); // 空闲对象,空闲多长时间会被驱逐出池里 connectionPoolConfig.setTimeBetweenEvictionRunsMillis(1000L * 30L); // 驱逐线程30秒执行一次 connectionPoolConfig.setNumTestsPerEvictionRun(-1); // -1,表示在驱逐线程执行时,测试所有的空闲对象 } public int getConnectionPoolMaxTotal() { return this.connectionPoolConfig.getMaxTotal(); } public void setConnectionPoolMaxTotal(int connectionPoolMaxTotal) { this.connectionPoolConfig.setMaxTotal(connectionPoolMaxTotal); } public int getConnectionPoolMaxIdle() { return this.connectionPoolConfig.getMaxIdle(); } public void setConnectionPoolMaxIdle(int connectionPoolMaxIdle) { this.connectionPoolConfig.setMaxIdle(connectionPoolMaxIdle); } public int getConnectionPoolMinIdle() { return this.connectionPoolConfig.getMinIdle(); } public void setConnectionPoolMinIdle(int connectionPoolMinIdle) { this.connectionPoolConfig.setMinIdle(connectionPoolMinIdle); } public boolean getLifo() { return this.connectionPoolConfig.getLifo(); } public void setLifo(boolean lifo) { this.connectionPoolConfig.setLifo(lifo); } public long getMaxWaitMillis() { return this.connectionPoolConfig.getMaxWaitMillis(); } public void setMaxWaitMillis(long maxWaitMillis) { this.connectionPoolConfig.setMaxWaitMillis(maxWaitMillis); } public long getMinEvictableIdleTimeMillis() { return this.connectionPoolConfig.getMinEvictableIdleTimeMillis(); } public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) { this.connectionPoolConfig.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); } public long getSoftMinEvictableIdleTimeMillis() { return this.connectionPoolConfig.getSoftMinEvictableIdleTimeMillis(); } public void setSoftMinEvictableIdleTimeMillis(long softMinEvictableIdleTimeMillis) { this.connectionPoolConfig.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis); } public int getNumTestsPerEvictionRun() { return this.connectionPoolConfig.getNumTestsPerEvictionRun(); } public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) { this.connectionPoolConfig.setNumTestsPerEvictionRun(numTestsPerEvictionRun); } public boolean getTestOnCreate() { return this.connectionPoolConfig.getTestOnCreate(); } public void setTestOnCreate(boolean testOnCreate) { this.connectionPoolConfig.setTestOnCreate(testOnCreate); } public boolean getTestOnBorrow() { return this.connectionPoolConfig.getTestOnBorrow(); } public void setTestOnBorrow(boolean testOnBorrow) { this.connectionPoolConfig.setTestOnBorrow(testOnBorrow); } public boolean getTestOnReturn() { return this.connectionPoolConfig.getTestOnReturn(); } public void setTestOnReturn(boolean testOnReturn) { this.connectionPoolConfig.setTestOnReturn(testOnReturn); } public boolean getTestWhileIdle() { return this.connectionPoolConfig.getTestWhileIdle(); } public void setTestWhileIdle(boolean testWhileIdle) { this.connectionPoolConfig.setTestWhileIdle(testWhileIdle); } public long getTimeBetweenEvictionRunsMillis() { return this.connectionPoolConfig.getTimeBetweenEvictionRunsMillis(); } public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) { this.connectionPoolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); } public String getEvictionPolicyClassName() { return this.connectionPoolConfig.getEvictionPolicyClassName(); } public void setEvictionPolicyClassName(String evictionPolicyClassName) { this.connectionPoolConfig.setEvictionPolicyClassName(evictionPolicyClassName); } public boolean getBlockWhenExhausted() { return this.connectionPoolConfig.getBlockWhenExhausted(); } public void setBlockWhenExhausted(boolean blockWhenExhausted) { this.connectionPoolConfig.setBlockWhenExhausted(blockWhenExhausted); } public boolean getJmxEnabled() { return this.connectionPoolConfig.getJmxEnabled(); } public void setJmxEnabled(boolean jmxEnabled) { this.connectionPoolConfig.setJmxEnabled(jmxEnabled); } public String getJmxNameBase() { return this.connectionPoolConfig.getJmxNameBase(); } public void setJmxNameBase(String jmxNameBase) { this.connectionPoolConfig.setJmxNameBase(jmxNameBase); } public String getJmxNamePrefix() { return this.connectionPoolConfig.getJmxNamePrefix(); } public void setJmxNamePrefix(String jmxNamePrefix) { this.connectionPoolConfig.setJmxNamePrefix(jmxNamePrefix); } //------------------------------------------- debug sticky serverlist public boolean getDebug() { return debug; } public void setDebug(String debug) { this.debug = Boolean.parseBoolean(debug); } public boolean getStickySession() { return this.stickySession; } public void setStickySession(String stickySession) { this.stickySession = Boolean.parseBoolean(stickySession); } public String getServerlist() { return serverlist; } public void setServerlist(String serverlist) { this.serverlist = serverlist; } public String getSocketTO() { return socketTO; } public void setSocketTO(String socketTO) { this.socketTO = socketTO; } }