我们知道Jedis在处理Redis的单机版和集群版时是完全不同的,有可能在开发的时候使用的是单机版,但是当项目上线后使用的则是集群版。这就需要能够方便的在单机版和集群版之间进行切换。我们的做法便是定义一个Jedis接口类,然后新建两个实现类来分别处理单机版和集群版,最后在Spring容器中进行配置管理即可。
首先在taotao-content-interface工程下新建一个包com.taotao.jedis.service并在该包下新建一个接口类JedisClient,如下图所示。
JedisClient接口类的代码如下:
package com.taotao.jedis.service;
public interface JedisClient {
//Redis SET命令用于在Redis键中设置一些字符串值
String set(String key, String value);
//根据key去查询相应的值
String get(String key);
//判断key在Redis缓存中是否存在
Boolean exists(String key);
//设置key的过期时间
Long expire(String key, int seconds);
//Redis TTL 命令以秒为单位返回 key 的剩余过期时间
Long ttl(String key);
//Redis Incr 命令将 key 中储存的数字值增一
Long incr(String key);
/**
* Redis Hset 命令用于为哈希表中的字段赋值 。
* 如果哈希表不存在,一个新的哈希表被创建并进行 HSET 操作。
* 如果字段已经存在于哈希表中,旧值将被覆盖。
* @param key
* @param field
* @param value
* @return
*/
Long hset(String key, String field, String value);
//Redis Hget 命令用于返回哈希表中指定字段的值。
String hget(String key, String field);
//Redis Hdel 命令用于删除哈希表 key 中的一个或多个指定字段,不存在的字段将被忽略。
Long hdel(String key, String... field);
}
接着我们到taotao-content-service工程下新建一个com.taotao.jedis.service.impl包,并在该包下新建两个JedisClient的实现类,分别是单机版实现类JedisClientPool和集群版实现类JedisClientCluster。单机版实现类如下:
package com.taotao.jedis.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import com.taotao.jedis.service.JedisClient;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class JedisClientPool implements JedisClient {
@Autowired
private JedisPool jedisPool;
@Override
public String set(String key, String value) {
Jedis jedis = jedisPool.getResource();
String result = jedis.set(key, value);
jedis.close();
return result;
}
@Override
public String get(String key) {
Jedis jedis = jedisPool.getResource();
String result = jedis.get(key);
jedis.close();
return result;
}
@Override
public Boolean exists(String key) {
Jedis jedis = jedisPool.getResource();
Boolean result = jedis.exists(key);
jedis.close();
return result;
}
@Override
public Long expire(String key, int seconds) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.expire(key, seconds);
jedis.close();
return result;
}
@Override
public Long ttl(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.ttl(key);
jedis.close();
return result;
}
@Override
public Long incr(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.incr(key);
jedis.close();
return result;
}
@Override
public Long hset(String key, String field, String value) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.hset(key, field, value);
jedis.close();
return result;
}
@Override
public String hget(String key, String field) {
Jedis jedis = jedisPool.getResource();
String result = jedis.hget(key, field);
jedis.close();
return result;
}
@Override
public Long hdel(String key, String... field) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.hdel(key, field);
jedis.close();
return result;
}
}
集群版实现类如下:
package com.taotao.jedis.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import com.taotao.jedis.service.JedisClient;
import redis.clients.jedis.JedisCluster;
public class JedisClientCluster implements JedisClient {
@Autowired
private JedisCluster jedisCluster;
@Override
public String set(String key, String value) {
return jedisCluster.set(key, value);
}
@Override
public String get(String key) {
return jedisCluster.get(key);
}
@Override
public Boolean exists(String key) {
return jedisCluster.exists(key);
}
@Override
public Long expire(String key, int seconds) {
return jedisCluster.expire(key, seconds);
}
@Override
public Long ttl(String key) {
return jedisCluster.ttl(key);
}
@Override
public Long incr(String key) {
return jedisCluster.incr(key);
}
@Override
public Long hset(String key, String field, String value) {
return jedisCluster.hset(key, field, value);
}
@Override
public String hget(String key, String field) {
return jedisCluster.hget(key, field);
}
@Override
public Long hdel(String key, String... field) {
return jedisCluster.hdel(key, field);
}
}
我们先来测试单机版如何使用,我们在单机版实现类JedisClientPool当中可以看到使用注入的方式注入JedisPool,要注入,Spring容器当中便要管理这个Bean,因此我们在taotao-content-service工程的src/main/resources/spring目录下新建一个applicationContext-jedis.xml配置文件来专门管理Jedis客户端的使用,内容如下(注意:下面的配置文件中关于开启注解的配置是为了在测试类中测试代码而添加的,因为使用测试类测试的话,不会加载其它配置文件,因此没有开启注解,因此需要这句配置,测试完后记得要删掉这个配置。还有就是单机版配置的端口6999是我在redis.conf中配置的,之所以没用默认的6379是因为redis集群使用了该端口)。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">
<!-- 开启注解 -->
<context:annotation-config/>
<!-- redis单机版 -->
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg name="host" value="192.168.156.21"/>
<constructor-arg name="port" value="6999"/>
</bean>
<bean id="jedisClientPool" class="com.taotao.jedis.service.impl.JedisClientPool"></bean>
</beans>
针对applicationContext-jedis.xml配置文件的内容有一点需要说明一下,我们看看下图,applicationContext-service.xml文件配置的扫描包的范围是com.taotao.content.service,那么如果我们不指定要扫描com.taotao.jedis.service包的话,能不能把JedisPool注入进来呢?答案是可以的,因为下图中<context:component-scan base-package="com.taotao.content.service"/>这句配置不仅指定了一个包扫描范围,还有一个功能就是开启注解(也就是同时具备两个功能),开启注解后写到Spring容器中的Bean都可以被外界成功注入。
下面我们新建一个测试类来进行测试,发现单机版没用问题,如下图所示。
代码如下:
@Test
public void testJedisClientPool(){
//初始化Spring容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-jedis.xml");
//从容器中获取JedisClient对象
JedisClient jedisClient = ctx.getBean(JedisClient.class);
//使用JedisClient操作Redis
jedisClient.set("jedisClient", "mytest");
String result = jedisClient.get("jedisClient");
System.out.println(result);
}
测试完了单机版,现在我们来测试集群版,在配置文件中注释掉单机版配置,添加集群版配置,如下所示。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">
<!-- 开启注解 -->
<context:annotation-config/>
<!-- redis单机版 -->
<!-- <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg name="host" value="192.168.156.21"/>
<constructor-arg name="port" value="6999"/>
</bean>
<bean id="jedisClientPool" class="com.taotao.jedis.service.impl.JedisClientPool"></bean> -->
<!-- redis集群版 -->
<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
<constructor-arg>
<set>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.156.15"/>
<constructor-arg name="port" value="6379"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.156.16"/>
<constructor-arg name="port" value="6379"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.156.17"/>
<constructor-arg name="port" value="6379"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.156.18"/>
<constructor-arg name="port" value="6379"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.156.19"/>
<constructor-arg name="port" value="6379"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.156.20"/>
<constructor-arg name="port" value="6379"/>
</bean>
</set>
</constructor-arg>
</bean>
<bean id="jedisClientCluster" class="com.taotao.jedis.service.impl.JedisClientCluster"></bean>
</beans>
添加完集群配置后,我们测试方法不用做任何修改,再运行一下,如下图所示,运行正常。
我们再到集群中任何一个节点去检查一下,比如我在192.168.156.17这个节点上使用客户端连接集群,使用命令get jedisClient来获取它的值,发现jedisClien被保存到了槽号为13154的上面,该槽号在192.168.156.18上,如下所示,说明确实保存到集群当中了。
[root@redis3 bin]# ./redis-cli -h 192.168.156.17 -p 6379 -c
192.168.156.17:6379> get jedisClient
-> Redirected to slot [13154] located at 192.168.156.18:6379
"mytest"
192.168.156.18:6379>
这样,以后我们只需修改Spring配置文件便可轻松在单机版和集群版进行切换。最后记得把applicationContext-jedis.xml文件中用于测试的开启注解的配置<context:annotation-config/>去掉,因为在applicationContext-service.xml文件中已经开启过注解了,系统运行会把所有的配置文件都加载进来,因此只需一处开启注解就可以了。
至此,用Spring容器来管理单机版和集群版Redis实现类便学习完了。