13.始源之地:Vert.x集成
考槃在涧,硕人之宽。独寐寤言,永矢弗谖。——佚名《国风·卫风》
「壹」Vert.x子项目
Vert.x从3.x开始,就将曾经的工具箱重新进行了模块化设计,您可以在官方文档中看到很多相关子项目(2.x中的模块化完全是灾难级的):
可能您会困惑,如果使用Zero,是不是就用不了这些相关的子项目了呢?答案是否定的,在Zero中您可以开发连接点程序,有了它您可以直接和Vert.x提供的官方子项目集成(类似MySQL Client
),也可以和Zero中设计的标准插件集成。Zero中的标准插件主要源起于实战,有些插件是Vert.x的子项目未提供的,而两种插件的引入使用统一的模式,Zero的玩法不一定最炫,但铁定会让您眼前一亮!
ifx
全称为infix
,翻译为“中缀、插入”。
Zero的子项目vertx-ifx
中包含了目前支持的所有插件,这些插件的开发流程都遵循了本章节的思路,其中还包含类似Neo4j、ElasticSearch、Excel等官方不支持的集成,一旦您学会了本章完整的开发思路,那么您的项目自然如虎添翼。目前的插件如下表:
项目名 | 类型 | 含义 |
---|---|---|
zero-ifx-es | Zero | ElasticSearch功能模块。 |
zero-ifx-excel | Zero | Excel导入导出功能模块(可直连Jooq功能模块)。 |
zero-ifx-feign | Zero | Feign功能模块。 |
zero-ifx-history | Zero | 系统读写日志历史数据库(第二库)。 |
zero-ifx-iqiy | Zero | Qiy爱奇艺视频客户端。 |
zero-ifx-neo4j | Zero | Neo4j的非SQL数据库图库集成模块。 |
zero-ifx-shell | Zero | 命令行工具抽象框架。 |
zero-ifx-sms | Zero | 阿里云手机短信服务。 |
zero-ifx-native | Vertx | MySQL和PgSQL客户端专用集成(标准)。 |
zero-ifx-mongo | Vertx | Mongo数据库客户端。 |
zero-ifx-redis | Vertx | Redis功能模块。 |
表格中的类型标识了该插件是Vert.x集成插件还是Zero的集成插件,本章不去剖析部分复杂的插件用法,后续会有单独的章节讲解,主要告诉读者:
如何在Zero中开发这种插件项目以及连接点程序(如何扩展)。
如何在您的Agent/Worker组件中使用这些扩展。
这些插件的设计以单一职责为原则,项目本身比较小,代码不多,目的也是让您在选择时可直接根据所需按需引入。
1.1. MySQL孤岛
1.1.1. 插件分析
Zero中使用了MySQL,但由于动态建模的影响,并没有使用Vert.x中的MySQL Client
,而是将Jooq标准化了。有关MySQL Client
的引入目前存在于zero-ifx-native
项目中,它只包含了一个代码文件(读者无需自己开发):
package io.vertx.up.plugin.jdbc;
import io.vertx.core.Vertx;
import io.vertx.ext.asyncsql.MySQLClient;
import io.vertx.ext.sql.SQLClient;
import io.vertx.up.annotations.Plugin;
import io.vertx.up.eon.Plugins;
import io.vertx.up.fn.Fn;
import io.vertx.up.plugin.Infix;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@Plugin
@SuppressWarnings("unchecked")
public class MySqlInfix implements Infix {
private static final String NAME = "ZERO_MYSQL_POOL";
private static final ConcurrentMap<String, SQLClient> CLIENTS
= new ConcurrentHashMap<>();
private static void initInternal(final Vertx vertx,
final String name) {
Fn.pool(CLIENTS, name, () ->
Infix.init(
Plugins.Infix.MYSQL,
(config) -> MySQLClient.createShared(vertx, config, name),
MySqlInfix.class
)
);
}
public static void init(final Vertx vertx) {
initInternal(vertx, NAME);
}
public static SQLClient getClient() {
return CLIENTS.get(NAME);
}
@Override
public SQLClient get() {
return getClient();
}
}
把它称为孤岛,就是因为整个zero-ifx-native
项目中只有这个文件,而这个文件却包含了很多巧思,也包含了Zero插件结构的骨架代码。 接口io.vertx.up.plugin.Infix
是Zero中为第三方功能模块设计的插件接口,实现该接口的类必须包含两个基本规范:
这是一个插件,必须被@Plugin(
io.vertx.up.annotations.Plugin
)注解。这个插件必须包含初始化静态方法(根据Vertx实例初始化插件):
public static void init(final Vertx vertx)
Zero中的插件连接点实现了池化客户端,如MySqlInfix
构造完成后的完整结构如下:
默认情况下,您获取的客户端引用直接和ZERO_MYSQL_POOL
绑定,Zero中和Vert.x集成的所有Infix
目前的版本都没扩展第二客户端,是否扩展最终取决于您的实际项目需求,上边代码中的插件您可以直接使用。
1.1.2. 插件使用
本章讲解如何在Zero中使用Infix
插件。
第一步:先在您的项目pom.xml
文件中引入该插件的依赖,由于Zero中所有vertx-ifx
子项目都已经定义过版本,所以可省略<version>
标签:
<dependency>
<groupId>cn.vertxup</groupId>
<artifactId>zero-ifx-native</artifactId>
<!-- 版本部分可省略,如果编译通不过,就使用下边这种。-->
<version>${zero.version}</version>
</dependency>
第二步:在项目中书写以下配置文件(以MySQL为例):
src/main/resources/vertx.yml
src/main/resources/vertx-inject.yml
src/main/resources/vertx-mysql.yml
上述三个文件内容如下:
vertx.yml片段
zero:
# lime专用扩展,默认会读取vertx-inject.yml,所以不需配置它;
# 此处的mysql表示Zero会去读取vertx-mysql.yml配置文件
lime: mysql
vertx:
instance:
# 未显示实例列表
vertx-mysql.yml内容如:
mysql:
host: localhost
port: 3306
username: root
password: ????
database: DB_IOP
vertx-inject.yml内容如:
# MySQL插件引入
mysql: io.vertx.up.plugin.jdbc.MySqlInfix
第三步:完成了上述配置后,您就可以直接在您的Agent或Worker组件中使用SQLClient
了,参考下边代码:
Agent代码
package cn.vertxup.mysql;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.sql.SQLClient;
import io.vertx.up.annotations.EndPoint;
import io.vertx.up.annotations.Plugin;
import javax.inject.infix.MySql;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@EndPoint
@Path("/hi/mysql")
public class MySqlAgent {
@Plugin
private transient SQLClient clientA;
@MySql
private transient SQLClient clientB;
@GET
@Path("/client")
public JsonObject hiAgent() {
final JsonObject response = new JsonObject();
response.put("clientA", this.clientA.toString());
response.put("clientB", this.clientB.toString());
return response;
}
}
{
"data": {
"clientA": "io.vertx.ext.asyncsql.impl.ClientWrapper@225b8ca6",
"clientB": "io.vertx.ext.asyncsql.impl.ClientWrapper@225b8ca6"
}
}
从响应结果可以知道,实际clientA
和clientB
引用了同一个对象,在整个环境中,都指向了ZERO_MYSQL_POOL
绑定的SQLClient
。上边注解部分的代码使用了依赖注入(Worker和Agent组件中代码相同),如果不使用依赖注入,则您可以使用下边代码获取:
// 这种代码在非Agent/Worker环境中尤其有用,比如工具类中。
final SQLClient client = MySqlInfix.getClient();
值的注意的是在Vert.x的3.9.8中(不知哪个版本开始),原来的vertx-mysql-postgresql-client
项目已经被废弃了,那是不是本章内容无用了呢?其实不然,虽然废弃了原来的SQLClient,但还引入了MySQLClient
以及PgSQLClient
,只是分得更细了,后续版本中我会更新Zero的Vert.x集成部分的代码,将native
拆成不同的子项目来对待,但整体思路以及玩法和本章节的内容保持高度一致,读者就不用去困惑了。
javax.inject.infix
包中的注解为保留注解,后续版本扩展时会根据不同功能执行拓展,如果是您自己定义的插件,直接使用标准的io.vertx.up.annotations.Plugin
即可。
1.2. Mongo
前一个章节讲解了zero-ifx-native
项目的内容、用法、以及Zero中插件的开发和使用思路,本章节使用同样的思路来分析zero-ifx-mongo
,这个项目是从最早的手机实战中延生出来的子项目,当初使用了MongoDB
作为数据库。回到前文思路中,先看看MongoInfix
的写法:
package io.vertx.tp.plugin.mongo;
import io.vertx.core.Vertx;
import io.vertx.ext.mongo.MongoClient;
import io.vertx.up.annotations.Plugin;
import io.vertx.up.eon.Plugins;
import io.vertx.up.fn.Fn;
import io.vertx.up.plugin.Infix;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@Plugin
@SuppressWarnings("unchecked")
public class MongoInfix implements Infix {
private static final String NAME = "ZERO_MONGO_POOL";
private static final ConcurrentMap<String, MongoClient> CLIENTS
= new ConcurrentHashMap<>();
private static void initInternal(final Vertx vertx,
final String name) {
Fn.pool(CLIENTS, name,() ->
Infix.init(
Plugins.Infix.MONGO,
(config) -> MongoClient.createShared(vertx, config, name),
MongoInfix.class
)
);
}
public static void init(final Vertx vertx) {
initInternal(vertx, NAME);
}
public static MongoClient getClient() {
return CLIENTS.get(NAME);
}
@Override
public MongoClient get() {
return getClient();
}
}
熟悉的味道、熟悉的配方,有了前一个章节的基础,理解这部分代码轻车熟路。它的基本配置如下:
Maven中引入
<dependency>
<groupId>cn.vertxup</groupId>
<artifactId>zero-ifx-mongo</artifactId>
<!-- 版本部分可省略,如果编译通不过,就使用下边这种。-->
<version>${zero.version}</version>
</dependency>
vertx-mongo.yml
具体配置项可参考官方的MongoOptions。
mongo:
db_name: xxx
post: xxx
host: xxx
connection_string: xxxx
username: xxx
password: xxx
vertx-inject.yml
mongo: io.vertx.tp.plugin.mongo.MongoInfix
这部分的代码就不详细叙述了,参考下边代码段:
// ..... import 部分
// Mongo客户端引用
import io.vertx.ext.mongo.MongoClient;
// Mongo专用注解
import javax.inject.infix.Mongo;
// ..... 主代码部分
// 插件引用
@Plugin
private transient MongoClient clientA;
@Mongo
private transient MongoClient clientB;
如此,您就可以直接在Zero的Agent和Worker组件中直接使用Mongo客户端了,若想要直接在工具类中使用,则可参考:
// 工具类中使用
final MongoClient client = MongoInfix.getClient();
1.3. Redis
Zero目前版本只支持三个和Vert.x集成项目的子项目:
zero-ifx-native
:MySQL/PgSQLzero-ifx-mongo
:MongoDBzero-ifx-redis
:Redis
本章我们分析一下Redis的基础用法,Redis的插件在Zero中是最复杂的,它支持的功能如下:
提供了和Mongo类似的
RedisInfix
实现Redis的异步访问。引入
Jedis
客户端新增同步访问(适用于旧场景)。可替换Vert.x Web中的Session存储介质,将
web-session
存储在Redis中替换原生存储。
还是回到本章重点Infix
的代码:
package io.vertx.tp.plugin.redis;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.redis.client.Redis;
import io.vertx.redis.client.RedisOptions;
import io.vertx.up.annotations.Plugin;
import io.vertx.up.eon.Plugins;
import io.vertx.up.log.Annal;
import io.vertx.up.plugin.Infix;
import io.vertx.up.util.Ut;
import redis.clients.jedis.Jedis;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@Plugin
@SuppressWarnings("unchecked")
public class RedisInfix implements Infix {
private static final String NAME = "ZERO_REDIS_POOL";
private static final Annal LOGGER = Annal.get(RedisInfix.class);
private static final ConcurrentMap<String, Redis> CLIENTS
= new ConcurrentHashMap<>();
private static final ConcurrentMap<String, Jedis> CLIENTS_SYNC
= new ConcurrentHashMap<>();
private static void initInternal(final Vertx vertx,
final String name) {
final RedisOptions options = Infix.init(Plugins.Infix.REDIS,
/*
* Two parts for
* - Redis reference
* - RedisOptions reference ( For Sync usage )
*/
(config) -> new RedisOptions(initSync(name, config)),
RedisInfix.class);
/*
* Redis client processing, ping to check whether it's Ok
*/
final Redis redis = Redis.createClient(vertx, options);
CLIENTS.put(name, redis);
redis.connect(handler -> {
/*
* If connected, keep
* If not connected, remove
* This kind of operation could let your system synced the Redis
* instead of Null Pointer in Unit Testing
*/
if (handler.succeeded()) {
LOGGER.info("[ Redis ] Connected successfully! {0}",
options.toJson().encode());
} else {
final Throwable ex = handler.cause();
if (Objects.nonNull(ex)) {
LOGGER.jvm(ex);
}
CLIENTS.remove(name);
}
});
}
private static JsonObject initSync(
final String name,
final JsonObject options) {
if (!CLIENTS_SYNC.containsKey(name)) {
final String host = options.getString("host");
final Integer port = options.getInteger("port");
final Jedis client = new Jedis(host, port);
// Auth
final String password = options.getString("password");
if (Ut.notNil(password)) {
final String username = options.getString("username");
if (Ut.isNil(username)) {
client.auth(password);
} else {
client.auth(username, password);
}
}
try {
client.ping();
CLIENTS_SYNC.put(name, client);
} catch (final Throwable ex) {
LOGGER.jvm(ex);
}
}
return options;
}
public static void init(final Vertx vertx) {
initInternal(vertx, NAME);
}
public static Redis getClient() {
return CLIENTS.get(NAME);
}
public static Jedis getJClient() {
return CLIENTS_SYNC.get(NAME);
}
public static void disabled() {
CLIENTS.clear();
CLIENTS_SYNC.clear();
}
@Override
public Redis get() {
return getClient();
}
}
在Redis部分,除了Vert.x在集成中引入了新版的Redis异步访问部分,还包含了Jedis的同步访问部分(同步不支持JSR330),二者结合使得功能更加完善,基本代码如下:
Maven引入
<dependency>
<groupId>cn.vertxup</groupId>
<artifactId>zero-ifx-redis</artifactId>
<!-- 版本部分可省略,如果编译通不过,就使用下边这种。-->
<version>${zero.version}</version>
</dependency>
vertx-redis.yml
redis:
post: xxx
host: xxx
vertx-inject.yml
redis: io.vertx.tp.plugin.redis.RedisInfix
使用部分参考下边代码段:
// ..... import 部分
// Redis客户端引用
import io.vertx.redis.client.Redis;
// Jedis客户端引用
import redis.clients.jedis.Jedis;
// Redis专用注解
import javax.inject.infix.Redis;
// ..... 主代码部分
// 插件引用(注入模式只支持Redis,不支持Jedis)
@Plugin
private transient Redis clientA;
@Redis
private transient Redis clientB;
// 工具读取(异步)
final Redis client = RedisInfix.getClient();
// 同步唯一获取引用方式
final Jedis client = RedisInfix.getJClient();
那么到这里,整个Zero中目前牵涉的三个和Vert.x的集成就告一段落,根据本章节的内容,读者可以很快和MySQL、Mongo、Redis集成,并去详细体会Zero中Infix
插件的详细内容,后续版本中,我会根据实际项目需求将部分客户端内容标准化,当前版本则提供给读者自己发挥。最后强调一点,本章节所有的Infix
实现代码都是Zero已经提供的代码,使用时不需额外开发。
挑战:最后留一个挑战,您可以尝试自己去开发一个Infix彻底理解Zero中的插件结构。
「贰」内置插件
除了第一章节表格中枚举的Zero子项目以外,Zero中还有部分内置的Infix
插件,本章主要讲解一个特殊的内置插件MapInfix
;和Redis项目插件一样,Zero为了兼容部分遗留系统或老系统,通常都会开同步和异步双通道来做新旧的桥接,如果只支持异步不支持同步,虽然看起来更加Vert.x,但对很多项目的迁移将是灾难。
2.1. MapInfix
Vert.x中的SharedData数据结构是类似Hash表的一种结构,它不仅仅可以在本地环境使用,也可以在集群环境使用,Zero Extension中用来存储临时授权码就使用了该结构,为了同时支持同步和异步,Zero提供了一个特殊的SharedClient
,该客户端架构和MySQLClient
以及MongoClient
类似(Vert.x没有),而本章的MapInfix
就是用来访问该Client的插件。
MapInfix
的完整代码如下:
package io.vertx.tp.plugin.shared;
import io.vertx.core.Vertx;
import io.vertx.up.annotations.Plugin;
import io.vertx.up.eon.Plugins;
import io.vertx.up.fn.Fn;
import io.vertx.up.plugin.Infix;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@Plugin
@SuppressWarnings("all")
public class MapInfix implements Infix {
private static final String NAME = "ZERO_MAP_POOL";
private static final ConcurrentMap<String, SharedClient<String, Object>>
CLIENTS = new ConcurrentHashMap<>();
private static void initInternal(final Vertx vertx,
final String name) {
Fn.pool(CLIENTS, name,() ->
Infix.init(
Plugins.Infix.SHARED,
(config) -> SharedClient.createShared(vertx, config, name),
MapInfix.class
)
);
}
public static void init(final Vertx vertx) {
initInternal(vertx, NAME);
}
public static SharedClient<String, Object> getClient() {
return CLIENTS.get(NAME);
}
public static String getDefaultName() {
return NAME;
}
@Override
public SharedClient<String, Object> get() {
return getClient();
}
}
由于该插件是内置,所以基本使用代码中不需Maven的额外引入,直接可用。
vertx-shared.yml
shared:
# 默认模式是同步模式,如果要使用异步模式,则需打开该开关
async: true
vertx-inject.yml
shared: io.vertx.tp.plugin.shared.MapInfix
使用代码段如:
// ...import 导入部分
import io.vertx.tp.plugin.shared.SharedClient;
import io.vertx.up.annotations.Plugin;
// JSR330注入
@Plugin
private transient SharedClient client;
// 工具类中使用方法
final SharedClient client = SharedInfix.getClient();
2.2. SharedClient
2.2.1. 结构综述
由于当前插件的特殊性,SharedClient
是Zero提供的接口,本小节简单讲解该接口中常用的API函数,该客户端的完整图示如下:
每个SharedClient内部都包含了一个对应的同步引用(LocalMap)和异步引用(AsyncMap)。由于Vert.x中的LocalMap不能在集群环境中跨环境使用,vertx-shared.yml
中的配置会让SharedClient选择内部实现模式,如果是异步则使用AsyncMap,如果是同步则使用LocalMap,且只能二选一。
如果您要使用多个Map如何操作,您可以使用下边的API函数(图中的切换)。
SharedClient<K, V> switchClient(final String name)
上述API可以让您直接切换客户端引用,一旦切换后您就可以操作第二个SharedClient,Zero中保证每个名字下只有一个SharedClient实例,实现池化单件结构。
// name = ZERO_MAP_POOL
SharedClient client1 = MapInfix.getClient();
// name = test
SharedClient client2 = client1.switchClient("test");
2.2.2. 最小单元
SharedClient最小操作单元为io.vertx.up.atom.Kv
——该数据结构存储了一个key = value
的完整信息,包括键名、键值等,该类的完整实现代码如下:
package io.vertx.up.atom;
import java.util.Map;
import java.util.Objects;
/*
* [Data Structure]
* Definition for `key = value` pair here
* It stored `key = value` and act as Pair here for some spec usage
*/
public final class Kv<K, V> {
private K key;
private V value;
private Kv(final K key, final V value) {
this.key = key;
this.value = value;
}
public static <K, V> Kv<K, V> create() {
return new Kv<>(null, null);
}
public static <K, V> Kv<K, V> create(final K key,
final V value) {
return new Kv<>(key, value);
}
public final K getKey() {
return this.key;
}
public final V getValue() {
return this.value;
}
public void set(final K key, final V value) {
this.key = key;
this.value = value;
}
@Override
public final int hashCode() {
return Objects.hashCode(this.key) ^ Objects.hashCode(this.value);
}
@Override
public final boolean equals(final Object o) {
if (o == this) {
return true;
}
if (o instanceof Map.Entry) {
final Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
return Objects.equals(this.key, e.getKey()) &&
Objects.equals(this.value, e.getValue());
}
return false;
}
@Override
public String toString() {
return "Kv{" +
"key=" + this.key +
", value=" + this.value +
'}';
}
}
该结构和Map.Entry
类似,但比Map.Entry
更简化,Zero内部很多地方都使用了该数据结构。
2.2.3. 操作类API
同步所有API定义如下:
// 将 key = value 存储到SharedData中
Kv<K, V> put(K key, V value);
// 将 key = value 存储到SharedData中,expiredSecs秒后自动移除
Kv<K, V> put(K key, V value, int expiredSecs);
// 移除 key 对应的 key = value 键值对,返回刚移除的项
Kv<K, V> remove(K key);
// 读取 key 对应的 value 值
V get(K key);
// 读取 key 对应的 value,如果 once = true,则读取后移除
V get(K key, boolean once);
// 清除所有
boolean clear();
// 返回当前Map尺寸
int size();
// 返回当前Map所有 key 名集合
Set<K> keys();
异步所有API定义如下:
@Fluent
SharedClient<K, V> put(K key, V value,
Handler<AsyncResult<Kv<K, V>>> handler);
@Fluent
SharedClient<K, V> put(K key, V value, int expiredSecs,
Handler<AsyncResult<Kv<K, V>>> handler);
@Fluent
SharedClient<K, V> remove(K key,
Handler<AsyncResult<Kv<K, V>>> handler);
@Fluent
SharedClient<K, V> get(K key,
Handler<AsyncResult<V>> handler);
@Fluent
SharedClient<K, V> get(K key, boolean once,
Handler<AsyncResult<V>> handler);
@Fluent
SharedClient<K, V> clear(
Handler<AsyncResult<Boolean>> handler);
@Fluent
SharedClient<K, V> size(
Handler<AsyncResult<Integer>> handler);
@Fluent
SharedClient<K, V> keys(
Handler<AsyncResult<Set<K>>> handler);
简单汇总:
异步类型的API全部参考Vert.x子项目中的Client架构量身打造,且每个API都是
@Fluent
的,由于参考了Vert.x子项目,所以并不包含Future模式。这些API比Map常规API唯一多出来的两个功能是:
存储到Map中的项(key = value)可按秒计时,如果超时则Zero会自动移除该项。
可使用一次读取的函数,该项被消费后就直接从数据结构中移除。
2.3. Ux.Pool
Ux.Pool
是Zero提供的另外一个工具函数,它近似于Ux.Jwt
和Ux.Jooq
,提供了Zero中常用的函数(可以理解成SharedClient的Future模式的封装)。使用它的初始化代码如:
// 使用默认的SharedData,name = ZERO_MAP_POOL
Ux.Pool.on(); // UxPool 类型
// 使用带名称的SharedData,name = test
Ux.Pool.on("test"); // UxPool类型
实际上边代码片段最终返回了UxPool
类型,看看它开放的所有API定义:
public <K, V> Future<Kv<K, V>> put(final K key, final V value)
public <K, V> Future<Kv<K, V>> put(final K key, final V value, int expiredSecs)
public <K, V> Future<Kv<K, V>> remove(final K key)
public <K, V> Future<V> get(final K key)
public <K, V> Future<V> get(final K key, final boolean once)
public Future<Boolean> clear()
public Future<Integer> size()
public Future<Set<String>> keys()
该工具和SharedClient中的API维持了高度统一,所以只是转换了异步函数,转换成了Future
的返回结果以方便使用Zero的开发人员,最后提供一份内部使用临时授权码部分的调用代码给您参考:
// 读取授权码
@SuppressWarnings("all")
static <V> Future<V> code(final String key) {
final String codePool = CONFIG.getCodePool();
return Ux.Pool.on(codePool).remove(key)
.compose(value -> Ux.future((V) value.getValue()));
}
// 写入授权码,加入30秒的过期时间
static <V> Future<V> code(final String key, final V value) {
final String codePool = CONFIG.getCodePool();
final Integer codeExpired = CONFIG.getCodeExpired();
return Ux.Pool.on(codePool).put(key, value, codeExpired)
.compose(item -> Ux.future(item.getValue()));
}
「叁」小结
本文主要给您讲解了Zero如何和Vert.x中的子项目做集成,并且通过集成部分给您讲解了Zero中的插件Infix架构,可能有部分读者会困惑,为什么不直接在SharedClient
中提供Future模式?这和Vert.x中的子项目有关,为了和Vert.x中的大部分子项目高度统一,所以才提供了原生风格类似的异步API(全@Fluent模式结构),而扩展部分的API才会提供Future模式,简单说SharedClient几乎是参考Vert.x中子项目的各种Client仿造的。
目前Zero提供的工具类中,主要包含如下:
工具类 | 类型 | 含义 |
---|---|---|
Ux.Jooq.on(daoClass) | UxJooq | 和Jooq生成的VertxDAO绑定简化数据库访问。 |
Ux.Join.on() | UxJoin | 实现跨表访问,JOIN类型的读取、搜索、统一。 |
Ux.Pool.on() | UxPool | 和SharedData绑定可调Future模式的异步API。 |
Ux.Jwt | UxJwt | 和安全中Jwt相关的核心工具类。 |
Ux.Job.on() | UxJob | 获取任务管理器,启动、停止、恢复后台任务专用。 |