背景:做项目中需要通过客户端ID关闭客户端连接(对应命令client kill id 12345),但是使用jedis封装的clientKill方法,尝试了很多次,都没有效果。所以就尝试使用反射方式,直接执行Redis命令来解决该问题。
使用Jedis的Connection类直接执行Redis命令
import .*;
import ;
import ;
public class Test {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
try (Connection connection = new Connection("127.0.0.1") /*1.使用Connection连接Redis*/) {
// 2. 通过反射获取Connection中的sendCommand方法(protected Connection sendCommand(Command cmd, String... args))。
Method method = ("sendCommand", , String[].class);
(true); // 设置可以访问private和protected方法
// 3. 调用connection的sendCommand方法,第二个参数为执行的命令(比如set,get,client等),第三个参数为命令的参数。
// 3.1 该命令最终对应redis中为: set test-key test-value
(connection, , new String[]{"test-key", "test-value"});
// 4.获取Redis的命令执行结果
(());
}
}
}
到Redis中查看
127.0.0.1:6379> get test-key
"test-value"
其中需要注意的点
-
为一个枚举,redis的命令从这里面找,比如set,get,client等
-
() 可以获取到执行结果。获取的结果和使用redis-cli效果一样
除了这个之外, 还有其他的,如果()。 具体使用哪一个,需要根据命令来决定。
如果使用的不对,则会抛出类型转换异常。
封装成工具方法
public static List<String> execRedisCommand(Jedis jedis, String command, String... args) throws InvocationTargetException, IllegalAccessException {
cmd = (());
Client client = ();
Method method = (, "sendCommand", , String[].class);
(true);
(client, cmd, args);
try {
List<String> respList = new ArrayList<>();
Object response = ();
if (response instanceof List) {
for (Object itemResp : ((List) response)) {
(new String((byte[]) itemResp));
}
return respList;
} else {
return (new String((byte[]) response));
}
} catch (JedisException e) {
return (());
}
}
调用样例
Jedis jedis = new Jedis("127.0.0.1", 6379);
("mypass");
(execRedisCommand(jedis, "set23", "hello", "123").get(0));
maven
<!--MethodUtils来源-->
<dependency>
<groupId></groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
JedisCluster解决方案
getClusterNodes()
可以获取到所有的Redis节点和其对应的Jedis
对象。然后对你想要执行的节点进行上面的操作即可。
若不太明白上面这句话,请先来熟悉Redis集群的工作原理,然后再看就懂了