使用Spring + Jedis集成Redis

jopen 3年前

使用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