Redis的Java客户端Lettuce简介

环境

  • 操作系统:Ubuntu 20.04
  • Redis:6.2.6
  • 开发工具:IntelliJ IDEA 2022.1 (Community Edition)

Lettuce的官网( https://lettuce.io/core/release/reference/index.html )对Lettuce的描述是: Lettuce is a scalable thread-safe Redis client based on netty and Reactor. Lettuce provides synchronous, asynchronous and reactive APIs to interact with Redis. 翻译过来就是:Lettuce是可伸缩的、线程安全的Redis客户端,它基于netty和Reactor。Lettuce提供了同步、异步和反应式API来与Redis交互。

注:关于如何在Java项目中配置Lettuce,参见我另一篇文档。

Lettuce的“hello world”代码如下:

        RedisURI redisUri = RedisURI.builder().withHost("localhost").withPort(6379).build();
        
        RedisClient redisClient = RedisClient.create(redisUri);
        
        StatefulRedisConnection<String, String> connection = redisClient.connect();
        
        RedisCommands<String, String> syncCommands = connection.sync();

        syncCommands.set("mykey1", "hello");

        connection.close();
        
        redisClient.shutdown();

核心类/接口

Lettuce的核心如下:

  • RedisURI
  • RedisClient
  • StatefulConnection
  • RedisCommands

RedisURI

RedisURI 封装了Redis服务器的信息。可用以下几种方法来创建 RedisURI

  1. RedisURI.create("redis://localhost/");
  2. RedisURI.Builder.redis("localhost", 6379).auth("password").database(1).build();
  3. new RedisURI("localhost", 6379, 60, TimeUnit.SECONDS);

上面的“hello world”代码使用的是其中第2种方法。

注:连接Redis又可分为Standalone(单机),Sentinel(哨兵),Cluster(集群)等几种不同的模式。本文只涉及Standalone模式。

RedisClient

代表Redis的客户端,通过调用 RedisClient.create(redisUri) 方法来创建,最后别忘了调用 shutdown() 方法来关闭。

注:与之类似的还有 RedisClusterClient 类。

StatefulConnection

代表Redis连接,通过调用 redisClient.connect() 方法来创建,最后别忘了调用 close() 方法来关闭。

注: StatefulConnection 是根接口。本例中,调用 redisClient.connect() 方法返回的是其子接口 StatefulRedisConnection ,其实现类是 StatefulRedisConnectionImpl

StatefulConnection 还有其它子接口,如 StatefulRedisPubSubConnectionStatefulRedisSentinelConnection 等。

RedisCommands

前面提到,Lettuce提供了同步、异步和反应式API来与Redis交互,其对应不同的 RedisXxxCommands 接口:

  • RedisCommands :同步模式,通过 connection.sync() 方法创建;
  • RedisAsyncCommands :异步模式,通过 connection.async() 方法创建;
  • RedisReactiveCommands :反应式模式,通过 connection.reactive() 方法创建;

此外,每个接口还有支持发布-订阅的变种接口:

  • RedisPubSubCommands :同步模式,支持发布-订阅;
  • RedisPubSubAsyncCommands :异步模式,支持发布-订阅;
  • RedisPubSubReactiveCommands :反应式模式,支持发布-订阅;

RedisXxxCommands 非常类似于 redis-cli 工具,用来执行各种Redis命令。在 redis-cli 命令行可以运行的命令,基本上 RedisXxxCommands 都提供了对等的方法。

同步模式

参见上例。

异步模式

例如:

        RedisURI redisUri = RedisURI.builder().withHost("localhost").withPort(6379).build();

        RedisClient redisClient = RedisClient.create(redisUri);

        StatefulRedisConnection<String, String> connection = redisClient.connect();

        RedisAsyncCommands<String, String> asyncCommands = connection.async();

        asyncCommands.set("mykey1", "hello").thenAccept(System.out::println);

        Thread.sleep(1000);

        connection.close();

        redisClient.shutdown();

本例中, set() 方法是异步的,返回 RedisFuture 对象,可用 thenAccept() 方法来处理返回结果。这和Java 8中的 CompletableFuture 非常类似。

另外,因为使用了异步模式,为了防止主程序结束的太快,所以让主程序sleep了一会儿,以等待异步线程结束。

反应式模式

例如:

        RedisURI redisUri = RedisURI.builder().withHost("localhost").withPort(6379).build();

        RedisClient redisClient = RedisClient.create(redisUri);

        StatefulRedisConnection<String, String> connection = redisClient.connect();

        RedisReactiveCommands<String, String> reactiveCommands = connection.reactive();

        reactiveCommands.set("mykey1", "hello").subscribe(System.out::println);

        Thread.sleep(1000);

        connection.close();

        redisClient.shutdown();

本例中, set() 方法是异步的,返回 Mono 对象,可用 subscribe() 方法来订阅返回结果。

同样,因为反应式模式也是异步的,为了防止主程序结束的太快,所以让主程序sleep了一会儿,以等待异步线程结束。

发布-订阅

发布

代码如下:

        RedisURI redisUri = RedisURI.builder().withHost("localhost").withPort(6379).build();

        RedisClient redisClient = RedisClient.create(redisUri);

        StatefulRedisPubSubConnection<String, String> connection = redisClient.connectPubSub();

        RedisPubSubCommands<String, String> pubSubCommands = connection.sync();

        pubSubCommands.publish("mychannel1", "hello world");

        connection.close();

        redisClient.shutdown();

打开 redis-cli 命令行,订阅 mychannel1

127.0.0.1:6379> subscribe mychannel1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "mychannel1"
3) (integer) 1

然后运行程序,发布消息,在命令行就能捕获该消息:

1) "message"
2) "mychannel1"
3) "hello world"

订阅

代码如下:

        RedisURI redisUri = RedisURI.builder().withHost("localhost").withPort(6379).build();

        RedisClient redisClient = RedisClient.create(redisUri);

        StatefulRedisPubSubConnection<String, String> connection = redisClient.connectPubSub();

        connection.addListener(new RedisPubSubAdapter<>() {
            @Override
            public void subscribed(String channel, long count) {
                System.out.println("subscribed, channel: " + channel + ", count: " + count);
            }

            @Override
            public void message(String channel, String message) {
                System.out.println("channel: " + channel + ", message: " + message);
            }
        });

        RedisPubSubCommands<String, String> pubSubCommands = connection.sync();

        pubSubCommands.subscribe("mychannel1");

        Thread.sleep(10000);

        connection.close();

        redisClient.shutdown();

注意,需要调用 connection.addListener() 方法,指定“订阅成功”和“捕获消息”时的回调方法。

运行程序,监听消息(回调 subscribed() 方法):

subscribed, channel: mychannel1, count: 1

然后在命令行发布消息:

127.0.0.1:6379> publish mychannel1 "Are you OK?"
(integer) 1
127.0.0.1:6379> 

程序就会捕获该消息(回调 message() 方法):

channel: mychannel1, message: Are you OK?

10秒钟之后,程序退出。

上例是在命令行和程序之间做发布-订阅,当然,也可以在程序与程序之间做发布-订阅。

此外,也可以在多处订阅同一个channel,比如程序和命令行都订阅了 mychannel1 ,然后在另一个程序或者命令行发布消息,则程序和命令行都会收到消息。

线程池

使用Lettuce线程池需要Apache Commons Pool2的支持。在 pom.xml 文件中添加如下依赖:

        <dependency>
            <groupId>org.apache.commonsgroupId>
            <artifactId>commons-pool2artifactId>
            <version>2.11.1version>
        dependency>

程序代码如下:

        RedisURI redisUri = RedisURI.builder().withHost("localhost").withPort(6379).build();

        RedisClient redisClient = RedisClient.create(redisUri);

        GenericObjectPoolConfig<StatefulRedisConnection<String, String>> conf = new GenericObjectPoolConfig<>();

        conf.setMaxTotal(20);

        GenericObjectPool<StatefulRedisConnection<String, String>> pool =
                ConnectionPoolSupport.createGenericObjectPool(redisClient::connect, conf);

        StatefulRedisConnection<String, String> connection = pool.borrowObject();

        RedisCommands<String, String> syncCommands = connection.sync();

        syncCommands.set("mykey1", "hello");

        connection.close();

        pool.close();

        redisClient.shutdown();

你可能感兴趣的:(Java,DB,redis,java,数据库,lettuce)