使用Spring + Jedis集成Redis
使用Spring和Jedis完成分片Redis的集成
一、集成環境
Tomcat7
JDK1.7
Jedis-2.7.2
Spring-4.1.6
二、資源依賴
(省略,網上很多)
三、集成過程
1、配置資源池
這里使用Jedis的ShardedJedisPool來管理,我們定義該配置文件為:spring-redis.xml,全部內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.2.xsd">
<!-- 引入jedis配置文件 -->
<context:property-placeholder location="classpath:conf/properties/redis.properties"
ignore-unresolvable="true" />
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal">
<value>${redis.pool.maxActive}</value>
</property>
<property name="maxIdle">
<value>${redis.pool.maxIdle}</value>
</property>
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="true"/>
</bean>
<bean id="shardedJedisPool" class="redis.clients.jedis.ShardedJedisPool" scope="singleton">
<constructor-arg index="0" ref="jedisPoolConfig" />
<constructor-arg index="1">
<list>
<bean class="redis.clients.jedis.JedisShardInfo">
<constructor-arg name="host" value="${redis.uri}" />
</bean>
</list>
</constructor-arg>
</bean>
</beans>
幾個注意的點:
(1)如果你有多個數據源需要通過<context:property-placeholder管理,且不愿意放在一個配置文件里,那么一定要加上ignore-unresolvable=“true"
(2)注意新版的(具體從哪個版本開始不清楚,有興趣可以查一下)JedisPoolConfig的property name,不是maxActive而是maxTotal,而且沒有maxWait屬性,建議看一下Jedis源碼。
(3)ShardedJedisPool有多種構造函數,選擇你需要的(具體看源碼),示例中只初始化了一個分片,并使用了通過指定host的構造器(具體格式見下文),如果有集群,在<list>下增加新的<bean>即可。
2、準備redis.properties,內容如下:
redis.pool.maxActive=200 redis.pool.maxIdle=50 redis.pool.minIdle=10 redis.pool.maxWaitMillis=20000 redis.pool.maxWait=300 redis.uri = redis://password@127.0.0.1:6379/0 redis.timeout=30000
這里要注意redis.uri的格式:redis://[密碼]@[服務器地址]:[端口]/[db index]
建議大家使用這種方式,配置內容少,還能自定義db index,非常適合開發、測試和線上環境的切換
3、將spring-redis.xml加入web.xml的context中,如下:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/spring-redis.xml</param-value>
</context-param>
如果你有多個數據源通過spring管理(如mysql),則同時加載,如下:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/spring-mybatis.xml,classpath:conf/spring-redis.xml</param-value>
</context-param>
3、以上所有的配置已完成,接下來的代碼的實現
(1)推薦大家使用統一的類來管理Jedis實例的生成和回收,參考代碼如下:JedisDataSourceImpl.class
@Repository("jedisDS")
public class JedisDataSourceImpl implements JedisDataSource {
private static final Logger LOG = LoggerFactory.getLogger(JedisDataSourceImpl.class);
@Autowired
private ShardedJedisPool shardedJedisPool;
@Override
public ShardedJedis getRedisClient() {
ShardedJedis shardJedis = null;
try {
shardJedis = shardedJedisPool.getResource();
return shardJedis;
} catch (Exception e) {
LOG.error("[JedisDS] getRedisClent error:" + e.getMessage());
if (null != shardJedis)
shardJedis.close();
}
return null;
}
@Override
public void returnResource(ShardedJedis shardedJedis) {
shardedJedis.close();
}
@Override
public void returnResource(ShardedJedis shardedJedis, boolean broken) {
shardedJedis.close();
}
}
這里要注意的是Jedis實例的回收,從jedis2.6開始,原returnResource方式已經提示在后續版本中不再支持,所以不建議大家再用ShardedJedisPool里的returnResource和retureBrokenResource方法,雖然在2.7中還支持(畢竟是因為這兩個方法存在漏洞)。
(2)編寫具體的Jedis操作類(片斷):RedisClientTemplate.class
@Repository("redisClientTemplate")
public class RedisClientTemplate {
private static final Logger log = LoggerFactory.getLogger(RedisClientTemplate.class);
@Autowired
private JedisDataSource redisDataSource;
public void disconnect() {
ShardedJedis shardedJedis = redisDataSource.getRedisClient();
shardedJedis.disconnect();
}
/**
* 設置單個值
*
* @param key
* @param value
* @return
*/
public String set(String key, String value) {
String result = null;
ShardedJedis shardedJedis = redisDataSource.getRedisClient();
if (shardedJedis == null) {
return result;
}
boolean broken = false;
try {
result = shardedJedis.set(key, value);
} catch (Exception e) {
log.error(e.getMessage(), e);
broken = true;
} finally {
redisDataSource.returnResource(shardedJedis, broken);
}
return result;
}
/**
* 獲取單個值
*
* @param key
* @return
*/
public String get(String key) {
String result = null;
ShardedJedis shardedJedis = redisDataSource.getRedisClient();
if (shardedJedis == null) {
return result;
}
boolean broken = false;
try {
result = shardedJedis.get(key);
} catch (Exception e) {
log.error(e.getMessage(), e);
broken = true;
} finally {
redisDataSource.returnResource(shardedJedis, broken);
}
return result;
}
public Boolean exists(String key) {
Boolean result = false;
ShardedJedis shardedJedis = redisDataSource.getRedisClient();
if (shardedJedis == null) {
return result;
}
boolean broken = false;
try {
result = shardedJedis.exists(key);
} catch (Exception e) {
log.error(e.getMessage(), e);
broken = true;
} finally {
redisDataSource.returnResource(shardedJedis, broken);
}
return result;
}
public String type(String key) {
String result = null;
ShardedJedis shardedJedis = redisDataSource.getRedisClient();
if (shardedJedis == null) {
return result;
}
boolean broken = false;
try {
result = shardedJedis.type(key);
} catch (Exception e) {
log.error(e.getMessage(), e);
broken = true;
} finally {
redisDataSource.returnResource(shardedJedis, broken);
}
return result;
}
/**
* 在某段時間后失效
*
* @param key
* @param seconds
* @return
*/
public Long expire(String key, int seconds) {
Long result = null;
ShardedJedis shardedJedis = redisDataSource.getRedisClient();
if (shardedJedis == null) {
return result;
}
boolean broken = false;
try {
result = shardedJedis.expire(key, seconds);
} catch (Exception e) {
log.error(e.getMessage(), e);
broken = true;
} finally {
redisDataSource.returnResource(shardedJedis, broken);
}
return result;
}
/**
* 在某個時間點失效
*
* @param key
* @param unixTime
* @return
*/
public Long expireAt(String key, long unixTime) {
Long result = null;
ShardedJedis shardedJedis = redisDataSource.getRedisClient();
if (shardedJedis == null) {
return result;
}
boolean broken = false;
try {
result = shardedJedis.expireAt(key, unixTime);
} catch (Exception e) {
log.error(e.getMessage(), e);
broken = true;
} finally {
redisDataSource.returnResource(shardedJedis, broken);
}
return result;
}
public Long ttl(String key) {
Long result = null;
ShardedJedis shardedJedis = redisDataSource.getRedisClient();
if (shardedJedis == null) {
return result;
}
boolean broken = false;
try {
result = shardedJedis.ttl(key);
} catch (Exception e) {
log.error(e.getMessage(), e);
broken = true;
} finally {
redisDataSource.returnResource(shardedJedis, broken);
}
return result;
}
public boolean setbit(String key, long offset, boolean value) {
ShardedJedis shardedJedis = redisDataSource.getRedisClient();
boolean result = false;
if (shardedJedis == null) {
return result;
}
boolean broken = false;
try {
result = shardedJedis.setbit(key, offset, value);
} catch (Exception e) {
log.error(e.getMessage(), e);
broken = true;
} finally {
redisDataSource.returnResource(shardedJedis, broken);
}
return result;
}
public boolean getbit(String key, long offset) {
ShardedJedis shardedJedis = redisDataSource.getRedisClient();
boolean result = false;
if (shardedJedis == null) {
return result;
}
boolean broken = false;
try {
result = shardedJedis.getbit(key, offset);
} catch (Exception e) {
log.error(e.getMessage(), e);
broken = true;
} finally {
redisDataSource.returnResource(shardedJedis, broken);
}
return result;
}
public long setRange(String key, long offset, String value) {
ShardedJedis shardedJedis = redisDataSource.getRedisClient();
long result = 0;
if (shardedJedis == null) {
return result;
}
boolean broken = false;
try {
result = shardedJedis.setrange(key, offset, value);
} catch (Exception e) {
log.error(e.getMessage(), e);
broken = true;
} finally {
redisDataSource.returnResource(shardedJedis, broken);
}
return result;
}
public String getRange(String key, long startOffset, long endOffset) {
ShardedJedis shardedJedis = redisDataSource.getRedisClient();
String result = null;
if (shardedJedis == null) {
return result;
}
boolean broken = false;
try {
result = shardedJedis.getrange(key, startOffset, endOffset);
} catch (Exception e) {
log.error(e.getMessage(), e);
broken = true;
} finally {
redisDataSource.returnResource(shardedJedis, broken);
}
return result;
}
}
(3)好了,接下來在你的業務代碼里加載RedisClientTemplate.class就可以了。
來自:http://my.oschina.net/u/866380/blog/521658