一行 YAML 切换后端,一个注解覆盖全部场景。灵锁,让分布式锁像
@Transactional一样简单。
你是否也在这样写分布式锁?
java
// 场景一:Redisson 手动加锁
RLock lock = redissonClient.getLock("order:" + orderId);
try {
if (lock.tryLock(3, TimeUnit.SECONDS)) {
// 业务逻辑
}
} finally {
lock.unlock();
}
// 场景二:换 ZooKeeper?重写一遍。
// 场景三:本地调试?注释掉上面的代码。
// 场景四:上生产换集群模式?再重写一遍。
六个环境,六套锁代码。锁本身的逻辑只占 20%,剩下的 80% 都在处理连接、重试、超时、清理。
灵锁,就是为了消灭这 80%。
灵锁是什么?
灵锁(Flexible Lock) 是一个 Spring Boot Starter,提供统一的声明式分布式锁接口。它的核心理念只有一句话:
你用注解描述"锁什么",灵锁负责"怎么锁"。
java
@Locking(key = "#userId + '-' + #orderId")
public void processOrder(String userId, String orderId) {
// 只管业务,锁的事交给灵锁
}
没有 try-finally,没有手动 unlock(),没有后端适配代码。一把注解,六个后端,零行代码切换。
六把锁,一个接口
| 后端 | 配置值 | 适用场景 |
|---|---|---|
| JVM 本地锁 | standalone |
本地开发、单实例应用 |
| Redis 单机 | redis |
分布式,单节点 Redis |
| Redis 集群 | redis_cluster |
生产环境 Redis Cluster |
| Redis 哨兵 | redis_sentinel |
高可用 Redis 部署 |
| ZooKeeper | zookeeper |
已有 ZK 基础设施的团队 |
| 空实现 | none |
测试环境、临时关闭锁 |
切换只需要一行 YAML:
yaml
flexible:
lock:
lockType: redis # 改成 zookeeper?重启即可,代码不动一行
本地开发用 standalone,测试用 none,生产用 redis_cluster------同一套代码,三种姿态。
不只是"能用",而是"好用"
🎯 SpEL 动态锁键
锁键支持 Spring 表达式语言(SpEL),可以引用方法参数、甚至 Spring Bean:
java
// 引用方法参数
@Locking(key = "'order-' + #orderId")
public void updateOrder(String orderId) { ... }
// 调用 Spring Bean 生成动态键
@Locking(key = "@systemClock.getTime() + '-' + #userId")
public void syncUserData(String userId) { ... }
表达式编译结果会被缓存,热路径上零重复解析开销。
🔄 三种重试策略,从容应对竞争
| 策略 | 行为 | 适用场景 |
|---|---|---|
| 固定等待 | 每次等待相同时间 | 常规场景 |
| 指数退避 | 等待时间翻倍(含溢出保护) | 高竞争场景 |
| 随机退避 | 在区间内随机等待 | 避免惊群效应 |
yaml
flexible:
lock:
waitTime: 3000 # 基础等待 3 秒
retryCount: 3 # 最多重试 3 次
retryStrategyType: exponential # 指数退避
⚡ 传输故障快速失败
当 Redis 连接断开、ZooKeeper 超时时,灵锁立即中断重试循环,而不是傻傻地烧完所有重试次数。根因异常完整保留,排查问题不再靠猜。
🔇 lockType: none------优雅地"不锁"
这是灵锁最被低估的特性。
测试环境不需要锁?lockType: none。所有 @Locking 注解瞬间变成空操作 ,无需删代码、无需改逻辑、无需加 if 判断。
这不仅仅是方便------它意味着你的测试可以在无锁环境下全速运行,而生产代码一行不改。
🔌 无缝集成现有基础设施
已经在用 RedissonClient 或 CuratorFramework?灵锁会自动检测,不会重复创建连接池。你的现有配置,灵锁直接复用。
🧹 资源清理,善始善终
所有连接池都注册了 destroyMethod = "shutdown"。Spring 容器关闭时,Redis 连接、ZooKeeper 会话会被干净地释放,不会有连接泄漏的幽灵。
类级注解:批量生效,精准覆盖
java
@Locking(key = "'order-' + #orderId", waitTime = 5000)
@Service
public class OrderService {
// 继承类级配置:锁 order-{orderId},等待 5 秒
public void create(Order order) { ... }
// 方法级覆盖:换锁键,不重试
@Locking(key = "'strict-' + #orderId", retryCount = 0)
public void forceUpdate(Order order) { ... }
// 不加注解 = 不锁
public Order findByOrderId(String orderId) { ... }
}
继承、覆盖、豁免,三层控制粒度,一个注解搞定。
技术细节,见微知著
- Redisson 看门狗自动续期:锁不会在业务执行期间意外过期
- ZooKeeper Digest ACL 支持:安全集群也能用,市面上多数 Starter 缺失此能力
- 溢出安全的退避算法 :指数退避有位移溢出保护,随机退避用
long运算避免int截断 - 本地锁的"不删除"设计:解锁时不移除 Map 条目------移除会破坏互斥性,灵锁选择了正确的那条路
- 解锁失败不吞异常:方法体异常与解锁异常分别处理,不会互相掩盖
快速开始
xml
<dependency>
<groupId>io.github.wb04307201</groupId>
<artifactId>flexible-lock-spring-boot-starter</artifactId>
<version>1.1.9</version>
</dependency>
yaml
# application.yml
flexible:
lock:
lockType: redis
redis:
host: "redis://127.0.0.1"
port: 6379
java
@Locking(key = "#userId")
public void updateUser(String userId) {
// 就这么简单
}
三步。从零到跑通一个分布式锁。
谁在用灵锁?
- 🚀 初创团队:从单机到集群,一套锁代码平滑过渡,不欠技术债
- 🏢 中大型企业:多环境(dev/test/staging/prod)统一代码,配置驱动切换
- 🔧 中间件团队:作为基础设施组件集成到内部框架,提供锁能力给业务方
写在最后
分布式系统够复杂了,分布式锁不该是其中之一。
灵锁不重新发明轮子------它站在 Redisson 和 Curator 的肩膀上,把那些连接管理、重试逻辑、资源清理、环境切换的脏活累活,封装成一个优雅的 @Locking 注解。
你负责思考业务,灵锁负责锁住混乱。
📦 GitHub :wb04307201/flexible-lock
📜 许可证 :Apache 2.0
📦 Maven Central :io.github.wb04307201:flexible-lock-spring-boot-starter:1.1.9
如果这篇文章对你有帮助,欢迎 Star ⭐ 支持!你的一个小星星,是开源作者最大的动力。