Lettuce快速入门

最近在开发一个使用Redis协议包装HBase的Proxy服务器,一路写的很顺,客户端使用redis-py提供的execute_command方法也轻松搞定。但是在编写Java客户端的时候却遇到了难题,我们常用的Jedis不提供自定义指令,连反射这条路子都给堵死了,感觉陷入了僵局。难道需要自己改造Jedis的源代码么,代价有点大。

转念一想,Redis4.0插件化都出来了,有那么多的自定义指令,官方肯定有客户端的解决方案,果然,Lettuce【莴笋】冒出来了,945个Star,看来很受欢迎。

看Lettuce项目介绍,它是基于Netty开发的,提供了同步异步两种调用方法,支持Pipeline,也支持Redis Sentinel和Cluster,最重要的是它支持自定义指令。还在使用Java7以下的小伙伴们就要叹息了,Lettuce只支持Java8+,赶快升级吧。

好,我们来试试Lettuce,看看它好不好用,首先引入依赖

<dependency>
    <groupId>io.lettuce</groupId>
    <artifactId>lettuce-core</artifactId>
    <version>5.0.0.RELEASE</version>
</dependency>

再看看它的基本用法

public class LettuceTest {

	public static void main(String[] args) {
		RedisClient client = RedisClient.create("redis://localhost:6379/0");
		StatefulRedisConnection<String, String> connection = client.connect(); // 获取一个连接
		RedisCommands<String, String> commands = connection.sync(); // 获取同步指令集
		commands.set("dream-codehole", "Yui Aragaki");
		System.out.println(commands.get("dream-codehole"));
		commands.zadd("dreams-codehole", 10, "Yui Aragaki");
		commands.zadd("dreams-codehole", 8, "Elane Zhong");
		System.out.println(commands.zcard("dreams-codehole"));
		connection.close(); // 关闭连接
		client.shutdown(); // 关闭所有连接
	}
}

好像和Jedis用法一样简单。Lettuce还支持异步用法,我们来看看异步怎么用。

public class LettuceTest {

	public static void main(String[] args) {
		RedisClient client = RedisClient.create("redis://localhost:6379/0");
		StatefulRedisConnection<String, String> connection = client.connect(); // 获取一个连接
		RedisAsyncCommands<String, String> commands = connection.async(); // 获取异步指令集
		RedisFuture<String> future1 = commands.get("dream-codehole");
		future1.whenComplete((value, e) -> {
			System.out.println(value);
		});
		RedisFuture<Long> future2 = commands.zcard("dreams-codehole");
		future2.whenComplete((value, e) -> {
			System.out.println(value);
		});
		try {
			Thread.sleep(1000); // 等一会,保证结果在连接关闭之前都拿到了
		} catch (InterruptedException e1) {
		}
                connection.close();
		client.shutdown();
	}
}

使用也很简单,异步的结果都使用RedisFuture对象进行包装。RedisFuture对象提供了大量的回调方法,任君选择。注意关闭连接之前一定要等待一段时间,确保所有的指令都异步执行完了,否则你的回调方法会统一收到NULL。

在使用Redis一般不会只使用一个连接的,我们一般会使用连接池。Jedis提供了内置的JedisPool封装,拿来即用,内部使用的是Apache Commons提供的对象池来实现。Lettuce的连接池用起来也差不多。

public class LettuceTest {

	public static void main(String[] args) throws Exception {
		RedisClient client = RedisClient.create("redis://localhost:6379/0");
		GenericObjectPool<StatefulRedisConnection<String, String>> pool = ConnectionPoolSupport
				.createGenericObjectPool(() -> client.connect(), new GenericObjectPoolConfig());
		try (StatefulRedisConnection<String, String> connection = pool.borrowObject()) {
			RedisCommands<String, String> commands = connection.sync();
			commands.set("dream-codehole", "Yui Aragaki");
			System.out.println(commands.get("dream-codehole"));
			commands.zadd("dreams-codehole", 10, "Yui Aragaki");
			commands.zadd("dreams-codehole", 8, "Elane Zhong");
			System.out.println(commands.zcard("dreams-codehole"));
		}
		pool.close();
		client.shutdown();
	}
}

接下来我们进入最精彩的部分,也是Lettuce区别于Jedis最大的部分,Lettuce提供了自定义指令接口。实现自定义指令需要提供3个东西。

  1. 指令名称
  2. 参数
  3. 结果解码器
public class HBaseClient {

	private RedisCommands<String, String> commands;
	private StringCodec codec = new StringCodec();

	public boolean create(String table, List<String> families) {
		CommandArgs<String, String> args = new CommandArgs<>(codec);
		args.add(table);
		args.addKeys(families);
		return commands.dispatch(HBaseCommand.CREATE, new BooleanOutput<String, String>(codec), args);
	}
}

create指令的的参数是一个字符串列表,表名和列簇的字符串定义,返回结果就是一个bool值。在redis协议中,客户端指令参数就是一个字符串列表,没有复杂的结构,但是返回结果却是可以任意嵌套的,可以具有无限的深度。对于大部分指令,Lettuce内置提供的很多Output解码器足以应付,不能应付的部分,Lettuce提供了扩展的接口可以自定义。

内置丰富的解码器

我们看到所有的解码器都是继承了CommandOutput接口,当我们想要自定义指令时,继承这个接口就可以了,然后在子类里实现你想要的任意复杂的解码逻辑。

本文分享自微信公众号 - 码洞(codehole)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-12-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏C/C++基础

我所理解的C++反射机制

在实际的项目中,听到师兄说C++中用到了反射,出于好奇,就查阅相关资料,发现强大的C++本身并不支持反射,反而Java支持反射机制。当我得知这个事实时,一直唯C...

26730
来自专栏JAVA高级架构

开发十年,就只剩下这套Java开发体系了

以前我一直被公司和技术牵着走,并不是自己在选择技术,而是不自觉地被推到了这个位置上。想想有多少人对于自己将来要从事的职业和技术类型进行过深入思考和比较呢?当我跳...

13920
来自专栏chenssy

【死磕Java并发】----- 死磕 Java 并发精品合集

【死磕 Java 并发】系列是 LZ 在 2017 年写的第一个死磕系列,一直没有做一个合集,这篇博客则是将整个系列做一个概览。

16520
来自专栏battcn

一起来学SpringBoot | 第二十篇:轻松搞定数据验证(二)

一起来学SpringBoot | 第十九篇:轻松搞定数据验证(一) 中介绍了数据有效性校验的重要性, 也简单介绍了如何用轻松的方式搞定数据有效性校验,但是当系统...

12110
来自专栏Android机动车

圣诞雪花纷飞自定义View

github地址:https://github.com/shuaijia/JSBaseDemo/blob/master/app/src/main/java/co...

14030
来自专栏battcn

一起学并发编程 - 利用观察者模式监听线程状态

在Java多线程下,我们需要知道当前执行线程的状态是什么比如 运行, 关闭, 异常等状态的通知,而且不仅仅是更新当前页面。

8920
来自专栏Android机动车

使用Retrofit+RxJava实现带进度下载文件

Retrofit+RxJava已经是目前市场上最主流的网络框架,使用它进行平常的网络请求异常轻松,之前也用Retrofit做过上传文件和下载文件,但发现:使用R...

35510
来自专栏battcn

一起来学SpringBoot | 第十七篇:轻松搞定文件上传

文件上传和下载是 JAVA WEB中常见的一种操作,文件上传主要是 将文件通过IO流传输到服务器的某一个特定的文件夹下;刚开始工作那会一个上传文件常常花费小半天...

18920
来自专栏Android机动车

线程池之小结

多线程:解决多任务同时执行的需求,合理使用CPU资源。多线程的运行是根据CPU切换完成,如何切换由CPU决定,因此多线程运行具有不确定性。

8930
来自专栏微信公众号:Java团长

为什么学习Spring Boot?

我们知道,从 2002 年开始,Spring 一直在飞速的发展,如今已经成为了在Java EE(Java Enterprise Edition)开发中真正意义上...

11320

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励