命令界面:使用Java中的动态API处理Redis

Redis是一个数据存储,支持190多个已记录命令和450多个命令排列。 社区积极支持Redis开发; 每个主要的Redis版本都附带新命令。 今年,Redis向第三方供应商开放,以开发可扩展Redis功能的模块。 对于客户端开发人员和Redis用户而言,命令的增长和对即将发布的模块的跟踪是一项挑战。

命令增长

对于客户端库,Redis中的命令增长是一项具有挑战性的业务。 多个客户端公开一个类型化的API,该API为每个Redis API调用声明一个方法(函数)签名。 静态声明对使用很有帮助,但是大量的Redis命令使用大量方法签名污染了客户端。 某些命令可能以不同的方式执行,从而影响需要附加签名的响应类型( ZREVRANGEZREVRANGE … WITHSCORES )。 让我们仔细看看一些方法签名:

重新发行

# Get the values of all the given hash fields.
# 
# @example
#   redis.hmget("hash", "f1", "f2")def hmget(key, *fields, &blk)

杰迪斯

public List<String> hmget(final String key, final String... fields)

生菜

List<V>
public List<K> hmget(K key, K... fields)

声明的方法可为开发人员提供类型安全性和文档,但它们同时是静态的。 Redis引入新命令后,客户端供应商必须更改API,否则新命令将不可用。 大多数Redis客户端公开客户端调用API来执行自定义命令来解决此问题:

重新发行

client.call([:hmget, key] + fields)

杰迪斯

final byte[][] params = …;
jedis.sendCommand(HMGET, params);

生菜

lettuce.dispatch(CommandType.HMGET, new ValueListOutput<>(codec),
new CommandArgs<>(codec).addKey(key).addKey(field));

吉迪普斯

rce.accept(client -> client.sendCmd(Cmds.HMGET, "hash", "field1", "field2", …));

其他客户端(例如node_redis基于Redis命令创建函数原型。 这是对静态API的改进,因为它使API具有一定的灵活性。

构造Redis命令需要有关其请求和响应结构的知识。 这些知识被记录在调用代码内部的某个位置。 这很方便,因为您将其放在需要代码的地方,但是它也有一些缺点。 由于自定义命令是从方法内部运行的,因此自定义命令需要额外的精力才能重用。 不需要在许多客户端上找到的典型方法签名。 如果不遵循API组件方法,这种方法会使自省更具挑战性。 这是因为所有自定义命令仅使用不同的参数来调用同一方法。

具有固定参数列表的静态方法声明的性质仅限于接受所提供的参数。 方法调用的上下文控件不能通过该方法应用。 例如,Lettuce提供了一个同步API,该API可以控制所有命令的命令超时,但不能控制命令调用级别。

让我们通过动态API处理Redis。

动态API

动态API是编程接口,因为它们遵循约定,因此具有一定的灵活性。 从Resteasy客户端代理或Spring Data的查询派生中可以知道动态API。 两者都是生活在用户区代码中的接口。 Resteasy / Spring Data检查接口并通过提供Java代理来实现这些接口。 这些接口(代理)上的方法调用将被拦截,检查并转换为相应的调用。 让我们看一下这对于Java和Redis如何工作:

一个简单的命令界面

public interface MyRedisCommands {List<String> hmget(String key, String... values);}

上面的接口声明了一个方法: List<String > hmget(String key, String... fields) 。 我们可以从该声明中得出某些信息:

  • 它应该同步执行-结果类型中没有声明异步或反应性包装器
  • Redis命令方法返回一个String List -告诉我们有关命令结果的期望,因此我们期望使用Redis数组并将每个项目转换为字符串
  • 该方法名为hmget 。 因为这是唯一可用的详细信息,所以我们假设命令名为hmget
  • 定义了两个参数: String keyString... values 。 这告诉我们参数的顺序及其类型。 尽管Redis除了批量字符串外不接受任何其他参数类型,我们仍然可以对参数进行转换-我们可以从声明的类型中推断出它们的序列化。

从上面调用的命令如下所示:

commands.hmget("key", "field1", "field2");

并转换为Redis命令:

HMGET key field1 field2

接口上的声明带有两个有趣的属性:

  1. 有一个方法签名。 尽管这是一个显而易见的事实,但这是一个常见的可执行文件。 它允许通过搜索此方法的引用来快速分析呼叫者。
  2. 在方法签名上方有一个空格,理想用于文档目的。

多种执行模型

public interface MyRedisCommands {List<String> hmget(Timeout timeout, String key, String... values);RedisFuture<List<String>> mget(String... keys);Flux<String> smembers(String key);}

动态API允许返回类型的差异。 让我们看看这如何影响我们可以从其返回类型派生的事物。

  • 您已经知道hmget以阻塞方式执行。 但是,等等,那Timeout参数是什么? 这是一个自己的参数类型,可以在调用级别上声明超时。 基础执行将从参数应用超时,而不再是在连接级别设置的默认值。
  • mget声明一个RedisFuture返回类型,该返回类型包装StringListRedisFuture是用于异步执行的包装器类型,它返回一个句柄以在稍后阶段执行同步或方法链接。 该方法可以异步执行。
  • smembers使用String Flux 。 基于返回类型,我们可以期待两个属性: Flux是一个反应式执行包装器,它将延迟执行直到订阅者订阅Flux为止。 List类型消失了,因为Flux可以发出0..N项目,因此我们可以决定进行流式响应执行。

命令结构

public interface MyRedisCommands {List<String> mget(String... keys);@Command("MGET")RedisFuture<List<String>> mgetAsync(String... keys);@CommandNaming(strategy = DOT)double nrRun(String key, int... indexes)@Command("NR.OBSERVE ?0 ?1 -> ?2 TRAIN")List<Integer> nrObserve(String key, int[] in, int... out)
}

Java要求方法的名称或参数类型有所不同。 字节码级别仅支持返回类型的差异,但在代码中编写方法时则不支持。 如果要声明一个同步执行的方法和一个采用相同参数异步执行的方法,该怎么办? 您需要指定其他名称。 但是,这是否与先前解释的名称派生冲突? 是的

  • 仔细看看mgetmgetAsync 。 两种方法均旨在同步和异步执行MGET命令。 mgetAsync带有@Command注释,该命令为命令提供命令名称,并覆盖该方法否则将被命名为MGETASYNC的假设。
  • Redis对模块开放。 每个模块都可以通过提供新命令来扩展Redis,其中命令模式遵循<PREFIX>。<COMMAND>准则。 但是,Java方法名称中不允许使用点。 让我们使用@CommandNaming(strategy = DOT)将不同的命名策略应用于nrRun 。 骆驼驼峰(字母大小写的变化)通过在各个命令段之间放置一个点来表示,我们很NR.RUN从Neural Redis运行NR.RUN
  • 某些命令带有更复杂的语法,该语法不允许仅串联参数。 看一下NR.OBSERVE 。 它由三个静态部分组成,中间部分之间有参数。 该命令结构以类似命令的语言表示。 NR.OBSERVE ?0 ?1 -> ?2 TRAIN将命令描述为字符串,并为参数添加索引引用。 命令中的所有字符串部分都是常量,参数引用将替换为实际参数。

结论

将动态API应用于Redis可以将视图转移到新的视角。 它可以为用户提供简化的自定义命令方法,而不会牺牲可重用性。 方法声明的性质为调用者的文档记录和自省创造了条件。

动态API也对使用RESP的其他应用程序(例如Disque或Tile38)也有利 。

可从Sonatype的OSS Snapshot存储库https://oss.sonatype.org/content/repositories/snapshots/通过生菜获得实验性实现:

<dependency><groupId>biz.paluch.redis</groupId><artifactId>lettuce</artifactId><version>5.0.0-dynamic-api-SNAPSHOT</version>
</dependency>

使用RedisCommandFactory

RedisCommandFactory factory = new RedisCommandFactory(connection);TestInterface api = factory.getCommands(TestInterface.class);
String value = api.get("key");public interface TestInterface {String get(String key);@Command("GET")byte[] getAsBytes(String key);
}

参考

  • @Command :命令注释通过使用类似命令的语言来指定命令名称或整个命令结构。
  • @CommandNaming :用于指定命令命名策略的注释。
  • Timeout :包含超时的值对象。
  • RedisFuture :未来结果句柄。
  • Flux : Project Reactor发布者,用于执行0..N项目的反应式执行。

翻译自: https://www.javacodegeeks.com/2016/10/command-interfaces-approaching-redis-dynamic-apis-java.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/351389.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python数据库连接池DBUtils

DBUtils是Python的一个用于实现数据库连接池的模块 此连接池有两种连接模式&#xff1a; DBUtils提供两种外部接口&#xff1a; PersistentDB &#xff1a;提供线程专用的数据库连接&#xff0c;并自动管理连接。 PooledDB &#xff1a;提供线程间可共享的数据库连接&…

够用的 Python 写日志的知识——标准日志模块logging简介

前一段工作的时候用到了python写后台系统&#xff0c;需要把一些系统的行为记录下来。本着不要去重复发明轮子的精神&#xff0c;就去搜索了一下python的系统库本身是否有写日志的模块。果然有。python语言作为一门接口简单&#xff0c;标准库强大的语言&#xff0c;果然没有令…

vivox7刷linux系统,Vivo 找来宋仲基帮你送 X7

虽说有极致的 Xplay5 用来打品牌&#xff0c;但真正跑起量来&#xff0c;Vivo 实际上靠得还是以明星代言、外型、自拍等特性为卖点的中端产品线。这不&#xff0c;他们刚刚又在北京发布了全新的 X7 系列&#xff0c;这次找来了大势韩星宋仲基&#xff0c;美其名曰「有了你就有了…

Gradle配置

配置远程仓库 在gradle目录下的init.d目录中创建名为init.gradle文件&#xff0c;内容如下&#xff1a; allprojects{repositories {def REPOSITORY_URL http://localhost:8081/nexus/content/groups/public/all { ArtifactRepository repo ->if(repo instanceof MavenArti…

UML类图实例

首先是复习一下UML中九种图的理解&#xff1a;http://xhf123456789plain.blog.163.com/blog/static/172880482201192222144421/ 画用例图&#xff1a;http://xhf123456789plain.blog.163.com/blog/static/172880482201192221826110/ 下面是类图的实例&#xff08;好像大话设计中…

836c语言程序设计,2017年辽宁师范大学计算机应用研究所836C语言程序设计考研强化模拟题...

一、选择题1&#xff0e; 以下叙述中正确的是( )。A. 在scanf 函数的格式串中&#xff0c;必须有与输入项一一对应的格式转换说明符B. 只能在printf 函数中指定输入数据的宽度&#xff0c;而不能在scanf 函数中指定输入数据占的宽度C.scanf 函数中的字符串是提示程序员的&#…

days to_days_Java2Days 2012:Java EE

days to_daysJava2Days会议是东欧的主要活动&#xff0c;目的是介绍Java开发的最新趋势。 今年&#xff0c;该活动于10月25日至26日在保加利亚的索非亚举行。 我在那里&#xff0c;并有机会与一些来自SAP的同事一起品尝了一些最新的Java&#xff0c;云和移动内容&#xff0c;这…

c语言静态成员变量重名会怎么样,C++中静态成员函数与静态成员变量(static )...

C中静态成员函数与静态成员变量(static )这篇介绍了静态成员函数与静态成员变量&#xff0c;是我的读书笔记&#xff0c;我希望它够简短但又比较全面&#xff0c;起到复习的作用。如果有一些C知识记不清楚了&#xff0c;它可以帮你很快回忆起来。复习C语言的static关键字(1)加在…

JVM简单学习

jvm与字节码 jvm只需关注字节码文件 jvm由哪些部分构成 1.类加载子系统&#xff0c;将磁盘中的字节码文件加载到方法区的内存空间中 类加载器分两种&#xff1a;引导类加载器是jvm底层中用C和C语言写的 各个默认的类加载器的不同区别在于 各自默认负责要加载的类的目录不一…

谈一谈自己对依赖、关联、聚合和组合之间区别的理解

在学习面向对象设计对象关系时&#xff0c;依赖、关联、聚合和组合这四种关系之间区别比较容易混淆。特别是后三种&#xff0c;仅仅是在语义上有所区别&#xff0c;所谓语义就是指上下文环境、特定情景等。他们在编程语言中的体现却是基本相同的&#xff0c;但是基本相同并不等…

Java Bullshifier –生成大量随机代码库

生成大量随机Java应用程序的命令行工具 您一直在等待的命令行工具。 或不。 毕竟&#xff0c;这是很深奥的。 无论哪种方式&#xff0c;它对某些人都非常有用&#xff0c;而对其他人来说却是一个有趣的实用程序。 Bullshifier是由David Levanon和Hodaya Gamliel开发的内部Over…

二级c语言光盘,二级c语言(光盘).doc

1程序设计题&#xff1a; 请编写一个函数 unsigned fun (unsigned w ) w是一个大于10的无符号整数。例如&#xff1a;W值为5923&#xff0c;则函数返回923&#xff1b;W值为923&#xff0c;则函数返回23。if ( w >10000 ) w % 10000 ; 程序修改题: m i; 和 if( a[k]>a[m]…

设计模式六大原则(3):依赖倒置原则

定义&#xff1a; 高层模块不应该依赖低层模块&#xff0c;二者都应该依赖其抽象&#xff1b;抽象不应该依赖细节&#xff1b;细节应该依赖抽象。 问题由来&#xff1a;类A直接依赖类B&#xff0c;假如要将类A改为依赖类C&#xff0c;则必须通过修改类A的代码来达成。这种场景下…

Jirasearch 2.0狗粮:使用Lucene查找我们的Jira问题

几年前&#xff0c;我首先构建并发布了Jirasearch &#xff0c;它是用于薄型包装Lucene服务器的有趣的狗粮测试用例&#xff0c;以针对我们的Jira问题公开强大的搜索UI。 这很好地展示了Lucene的许多重要功能&#xff1a; 使用块联接查询来建模父文档&#xff08;原始的Jira问…

Highcharts教程--把js代码从html中抽离出来,放到单独的一个js文件中。由html页面调用...

1.html页面写法 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>第一个 Highcharts 图表</title><!-- 引入 jquery.js --><script src"static/jquery-3.3.1.min.js"><…

数据结构c语言版第16页,数据结构c语言版

数据结构c语言版[编辑]概述《数据结构C语言版》本书的前半部分从抽象数据类型的角度讨论各种基本类型的数据结构及其应用;后半部分主要讨论查找和排序的各种实现方法及综合分析比较出版信息作/译者&#xff1a;严蔚敏&#xff0c;吴伟民 出版社&#xff1a;清华大学出版社出版日…

C语言申请内存时堆栈大小限制

一直都有一个疑问&#xff0c;一个进程可以使用多大的内存空间&#xff0c;swap交换空间以及物理内存的大小&#xff0c;ulimit的stack size对进程的内存使用有怎样的限制&#xff1f;今天特亲自动手实验了一次&#xff0c;总结如下&#xff1a; 开辟一片内存空间有2种方式&…

微服务之数据同步Porter

Porter是一款数据同步中间件&#xff0c;主要用于解决同构/异构数据库之间的表级别数据同步问题。 背景 在微服务架构模式下深刻的影响了应用和数据库之间的关系&#xff0c;不像传统多个服务共享一个数据库&#xff0c;微服务架构下每个服务都要有自己的数据库。如果你想获得微…

C语言采用多文件的工程结构百度,C语言学习知识复习资料结构框架学习知识重点.doc...

C语言学习知识复习资料结构框架学习知识重点.doc .思维导图1C语言程序设计知识结构第一课 C语言程序设计基础思维导图2第一课 C语言程序设计基础本课主要知识点1.知识点C程序基础l C语言是一种结构化程序设计语言。三种基本结构顺序、选择、循环。例1(2010-09-11)以下关于结构化…

antlr_ANTLR –语义谓词

antlr用antlr解析简单的语法很简单 。 您要做的就是使用正则表达式描述您的语言&#xff0c;并让antlr生成词法分析器和解析器。 解析大型或复杂的语言有时会需要更多&#xff0c;因为仅使用正则表达式描述它们是困难的&#xff0c;甚至是不可能的。 语义谓词是在语法内部编写…