使用 java-db 整合 Redis
核心类是 nexus.io.redis.RedisPlugin、Redis、RedisDb。
依赖
在已能启动的 tio-boot 工程中加入以下依赖;已有依赖通过 dependencyManagement 统一版本。Jedis 在 java-db 中是 provided,应用需要显式提供。
<dependency>
<groupId>nexus.io</groupId>
<artifactId>java-db</artifactId>
<version>1.5.9</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.3.1</version>
</dependency>
下例显式选择 java-db 自带的 JdkSerializer。若使用插件默认的 FstSerializer,还需提供匹配的 FST 依赖;不要在已有数据上直接切换序列化协议。
验证连接与资源释放
启动本地 Redis 后运行下列独立入口。连接超时单位为毫秒,数据库编号为 0;有密码时设置环境变量 REDIS_PASSWORD。
import nexus.io.redis.Redis;
import nexus.io.redis.RedisPlugin;
import nexus.io.redis.serializer.JdkSerializer;
public class RedisQuickStart {
public static void main(String[] args) {
RedisPlugin plugin = new RedisPlugin("main", "127.0.0.1", 6379,
2000, System.getenv("REDIS_PASSWORD"), 0);
plugin.setSerializer(JdkSerializer.me);
plugin.start();
try {
String pong = Redis.call("main", jedis -> jedis.ping());
Redis.call("main", jedis -> jedis.setex("demo:redis:hello", 60L, "hello"));
String value = Redis.call("main", jedis -> jedis.get("demo:redis:hello"));
System.out.println(pong + " " + value);
} finally {
plugin.stop();
}
}
}
预期输出 PONG hello。start() 创建连接池并注册实例,不代表已经验证服务可达;ping() 才实际访问服务。Redis.call 在调用结束后归还连接。Web 应用应在整个应用关闭时停止插件,不能每个请求都启停。
tio-boot 初始化
将配置类放在启动类扫描范围内。redis.timeout 单位为毫秒;cacheName 是应用内连接池名称,与 Redis database 编号不同。密码通过部署环境配置,不要提交真实密码。
redis.host=127.0.0.1
redis.port=6379
redis.timeout=2000
redis.database=0
redis.cacheName=main
import nexus.io.annotation.AConfiguration;
import nexus.io.annotation.Initialization;
import nexus.io.hook.HookCan;
import nexus.io.redis.Redis;
import nexus.io.redis.RedisPlugin;
import nexus.io.redis.serializer.JdkSerializer;
import nexus.io.tio.utils.environment.EnvUtils;
@AConfiguration
public class RedisConfiguration {
@Initialization
public void config() {
String name = EnvUtils.get("redis.cacheName", "main");
RedisPlugin plugin = new RedisPlugin(name,
EnvUtils.get("redis.host", "127.0.0.1"),
EnvUtils.getInt("redis.port", 6379),
EnvUtils.getInt("redis.timeout", 2000),
EnvUtils.getStr("redis.password"),
EnvUtils.getInt("redis.database", 0));
plugin.setSerializer(JdkSerializer.me);
plugin.config(pool -> {
pool.setMaxTotal(32);
pool.setMaxIdle(8);
pool.setTestWhileIdle(true);
});
plugin.start();
try {
Redis.call(name, jedis -> jedis.ping());
} catch (RuntimeException e) {
plugin.stop();
throw e;
}
HookCan.me().addDestroyMethod(plugin::stop);
}
}
如果 tio-boot-admin 已启用内置 TioAdminRedisDbConfiguration,应复用它注册的实例,不要同时添加上面的初始化类并注册同名池。未注册的名称会使 Redis.use(name) 返回 null。第一个实例是默认缓存,也可用 Redis.setMainCache(name) 显式选择。
RedisDb 与序列化
| 调用 | 数据格式及适用场景 |
|---|---|
Redis.use(name).set(key, value) / get(key) | 使用插件序列化器,双方需约定相同协议 |
Redis.call(name, j -> j.setex(key, 60L, value)) | Jedis 字符串 API,可跨语言共享 |
Redis.setStr(key, 60L, value) / getStr(key) | 默认缓存的字符串快捷方法 |
Redis.setBean(key, 60L, bean) / getBean(key, Type.class) | JSON 字符串形式的对象 |
不要在同一个键上混用对象序列化与原始字符串 API。与 Spring RedisTemplate 共享数据前,核对 key、hash field 和 value 的实际序列化器,参见 序列化互通。
直接调用 RedisDb.getJedis() 时,应使用 try-with-resources 关闭返回的 Jedis。优先使用 Redis.call 减少连接泄漏。Redis.callback 在同一线程内复用连接,但它本身不是 Redis 事务。
方法结果缓存与并发
RedisCacheInterceptor 与 CacheableModel 处理方法结果缓存。源码中的锁是 JVM 内的 ReentrantLock,不能视作多实例分布式互斥;注解应通过 AOP 代理调用才能生效。普通读穿缓存也需由业务决定空值处理、TTL、失效与并发回源策略。
数据操作、原子去重及锁的限制见 Redis 使用示例,签名见 Redis API。
相关源码
java-db/src/main/java/nexus/io/redis/RedisPlugin.java:连接池启停与序列化器。java-db/src/main/java/nexus/io/redis/Redis.java:缓存注册与 call/callback。java-db/src/main/java/nexus/io/redis/RedisDb.java:连接归还、数据操作、锁与事务。tio-boot-admin/tio-boot-admin-base/src/main/java/nexus/io/tio/boot/admin/config/TioAdminRedisDbConfiguration.java:后台初始化入口。
运行连接示例前,请确保 Redis 服务可用。
