package com.liuxinglanyue.session.redis; import java.io.IOException; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.apache.catalina.LifecycleException; import org.apache.catalina.Session; 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.JedisSentinelPool; import redis.clients.jedis.Protocol; import redis.clients.util.Pool; import com.liuxinglanyue.session.AbstractSessionManager; import com.liuxinglanyue.session.CustomSession; public class RedisSessionManager extends AbstractSessionManager { private final Log log = LogFactory.getLog(RedisSessionManager.class); protected String host = "localhost"; protected int port = 6379; protected int database = 0; protected String password = null; protected int timeout = Protocol.DEFAULT_TIMEOUT; protected String sentinelMaster = null; protected Set<String> sentinelSet = null; protected Pool<Jedis> connectionPool; protected JedisPoolConfig connectionPoolConfig = new JedisPoolConfig(); public final static String name = "RedisSessionManager"; /** * generate sessionId */ protected String generateCustomSessionId(String requestedSessionId) { Jedis jedis = null; String sessionId = null; String jvmRoute = getJvmRoute(); boolean error = false; try { jedis = acquireConnection(); if (null != requestedSessionId) { sessionId = requestedSessionId; if (jvmRoute != null) { sessionId += '.' + jvmRoute; } if (jedis.setnx(sessionId.getBytes(), NULL_SESSION) == 0L) { sessionId = null; } } else { do { sessionId = generateSessionId(); if (jvmRoute != null) { sessionId += '.' + jvmRoute; } } while (jedis.setnx(sessionId.getBytes(), NULL_SESSION) == 0L); } error = initSession(jedis, sessionId); } finally { if (jedis != null) { returnConnection(jedis, error); } } return sessionId; } @Override public Session createEmptySession() { return new CustomSession(this); } /** * 初始化DB连接 */ protected void initializeDatabaseConnection() throws LifecycleException { try { if (getSentinelMaster() != null) { Set<String> sentinelSet = getSentinelSet(); if (sentinelSet != null && sentinelSet.size() > 0) { connectionPool = new JedisSentinelPool(getSentinelMaster(), sentinelSet, this.connectionPoolConfig, getTimeout(), getPassword()); } else { throw new LifecycleException( "Error configuring Redis Sentinel connection pool: expected both `sentinelMaster` and `sentiels` to be configured"); } } else { connectionPool = new JedisPool(this.connectionPoolConfig, getHost(), getPort(), getTimeout(), getPassword()); } } catch (Exception e) { e.printStackTrace(); throw new LifecycleException("Error connecting to Redis", e); } } public void save(Session session, boolean forceSave) throws IOException { Jedis jedis = null; boolean error = true; try { jedis = acquireConnection(); error = saveInternal(jedis, session, forceSave); } catch (IOException e) { throw e; } finally { if (jedis != null) { returnConnection(jedis, error); } } } public byte[] loadSessionDataFromDB(String id) throws IOException { Jedis jedis = null; boolean error = true; try { log.trace("Attempting to load session " + id + " from Redis"); jedis = acquireConnection(); byte[] data = jedis.get(id.getBytes()); error = false; if (data == null) { log.trace("Session " + id + " not found in Redis"); } return data; } finally { if (jedis != null) { returnConnection(jedis, error); } } } public String dbSet(Object db, byte[] key, byte[] value) { if (null != db && db instanceof Jedis) { return ((Jedis) db).set(key, value); } throw new RuntimeException("db 为非Jedis !!!"); } public long dbExpire(Object db, byte[] key, int seconds) { if (null != db && db instanceof Jedis) { return ((Jedis) db).expire(key, seconds); } throw new RuntimeException("db 为非Jedis !!!"); } public void remove(Session session, boolean update) { Jedis jedis = null; boolean error = true; log.trace("Removing session ID : " + session.getId()); try { jedis = acquireConnection(); jedis.del(session.getId()); error = false; } finally { if (jedis != null) { returnConnection(jedis, error); } } } public void clear() { Jedis jedis = null; boolean error = true; try { jedis = acquireConnection(); jedis.flushDB(); error = false; } finally { if (jedis != null) { returnConnection(jedis, error); } } } public int getSize() throws IOException { Jedis jedis = null; boolean error = true; try { jedis = acquireConnection(); int size = jedis.dbSize().intValue(); error = false; return size; } finally { if (jedis != null) { returnConnection(jedis, error); } } } public String[] keys() throws IOException { Jedis jedis = null; boolean error = true; try { jedis = acquireConnection(); Set<String> keySet = jedis.keys("*"); error = false; return keySet.toArray(new String[keySet.size()]); } finally { if (jedis != null) { returnConnection(jedis, error); } } } protected void connectionDestroy() { connectionPool.destroy(); } protected Jedis acquireConnection() { Jedis jedis = connectionPool.getResource(); if (getDatabase() != 0) { jedis.select(getDatabase()); } return jedis; } protected void returnConnection(Jedis jedis, Boolean error) { if (error) { connectionPool.returnBrokenResource(jedis); } else { connectionPool.returnResource(jedis); } } protected void returnConnection(Jedis jedis) { returnConnection(jedis, false); } public String getHost() { return host; } public void setHost(String host) { this.host = host; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } public int getDatabase() { return database; } public void setDatabase(int database) { this.database = database; } public int getTimeout() { return timeout; } public void setTimeout(int timeout) { this.timeout = timeout; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getSentinels() { StringBuilder sentinels = new StringBuilder(); for (Iterator<String> iter = this.sentinelSet.iterator(); iter.hasNext();) { sentinels.append(iter.next()); if (iter.hasNext()) { sentinels.append(","); } } return sentinels.toString(); } public void setSentinels(String sentinels) { if (null == sentinels) { sentinels = ""; } String[] sentinelArray = sentinels.split(","); this.sentinelSet = new HashSet<String>(Arrays.asList(sentinelArray)); } public Set<String> getSentinelSet() { return this.sentinelSet; } public String getSentinelMaster() { return this.sentinelMaster; } public void setSentinelMaster(String master) { this.sentinelMaster = master; } 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); } }