组件讲解-分布式锁原理的详细剖析-下
在上篇文章中我们接受了分布式锁的切面实现的全部过程,而在本文中,本人将接着介绍分布式锁的方法级别的实现过程
依旧从自动装配作为入口来分析
ServiceLockAutoConfiguration
java
public class ServiceLockAutoConfiguration {
/**
* 分布式锁的key解析处理器
* */
@Bean(LockInfoType.SERVICE_LOCK)
public LockInfoHandle serviceLockInfoHandle(){
return new ServiceLockInfoHandle();
}
/**
* 锁管理
* */
@Bean
public ManageLocker manageLocker(RedissonClient redissonClient){
return new ManageLocker(redissonClient);
}
/**
* 锁工厂
* */
@Bean
public ServiceLockFactory serviceLockFactory(ManageLocker manageLocker){
return new ServiceLockFactory(manageLocker);
}
/**
* 分布式锁切面
* */
@Bean
public ServiceLockAspect serviceLockAspect(LockInfoHandleFactory lockInfoHandleFactory,ServiceLockFactory serviceLockFactory){
return new ServiceLockAspect(lockInfoHandleFactory,serviceLockFactory);
}
/**
* 分布式锁工具
* */
@Bean
public ServiceLockTool serviceLockUtil(LockInfoHandleFactory lockInfoHandleFactory,ServiceLockFactory serviceLockFactory){
return new ServiceLockTool(lockInfoHandleFactory,serviceLockFactory);
}
}ServiceLockAutoConfiguration是自动装配类,加载了 分布式锁的key解析处理器、分布式锁工厂、分布式锁切面、分布式锁工具的对象,而这个分布式锁工具 就是方法级别操作的api
ServiceLockTool
java
@AllArgsConstructor
public class ServiceLockTool {
private final LockInfoHandleFactory lockInfoHandleFactory;
private final ServiceLockFactory serviceLockFactory;
/**
* 没有返回值的加锁执行
* @param taskRun 要执行的任务
* @param name 锁的业务名
* @param keys 锁的标识
*
* */
public void execute(TaskRun taskRun,String name,String [] keys) {
execute(taskRun,name,keys,20);
}
/**
* 没有返回值的加锁执行
* @param taskRun 要执行的任务
* @param name 锁的业务名
* @param keys 锁的标识
* @param waitTime 等待时间
*
* */
public void execute(TaskRun taskRun,String name,String [] keys,long waitTime){
execute(LockType.Reentrant,taskRun,name,keys,waitTime);
}
/**
* 没有返回值的加锁执行
* @param lockType 锁类型
* @param taskRun 要执行的任务
* @param name 锁的业务名
* @param keys 锁的标识
*
* */
public void execute(LockType lockType,TaskRun taskRun,String name,String [] keys) {
execute(lockType,taskRun,name,keys,20);
}
/**
* 没有返回值的加锁执行
* @param lockType 锁类型
* @param taskRun 要执行的任务
* @param name 锁的业务名
* @param keys 锁的标识
* @param waitTime 等待时间
*
* */
public void execute(LockType lockType,TaskRun taskRun,String name,String [] keys,long waitTime) {
LockInfoHandle lockInfoHandle = lockInfoHandleFactory.getLockInfoHandle(LockInfoType.SERVICE_LOCK);
String lockName = lockInfoHandle.simpleGetLockName(name,keys);
ServiceLocker lock = serviceLockFactory.getLock(lockType);
boolean result = lock.tryLock(lockName, TimeUnit.SECONDS, waitTime);
if (result) {
try {
taskRun.run();
}finally {
lock.unlock(lockName);
}
}else {
LockTimeOutStrategy.FAIL.handler(lockName);
}
}
/**
* 有返回值的加锁执行
* @param taskCall 要执行的任务
* @param name 锁的业务名
* @param keys 锁的标识
* @return 要执行的任务的返回值
* */
public <T> T submit(TaskCall<T> taskCall,String name,String [] keys){
LockInfoHandle lockInfoHandle = lockInfoHandleFactory.getLockInfoHandle(LockInfoType.SERVICE_LOCK);
String lockName = lockInfoHandle.simpleGetLockName(name,keys);
ServiceLocker lock = serviceLockFactory.getLock(LockType.Reentrant);
boolean result = lock.tryLock(lockName, TimeUnit.SECONDS, 30);
if (result) {
try {
return taskCall.call();
}finally {
lock.unlock(lockName);
}
}else {
LockTimeOutStrategy.FAIL.handler(lockName);
}
return null;
}
/**
* 获得锁
* @param lockType 锁类型
* @param name 锁的业务名
* @param keys 锁的标识
*
* */
public RLock getLock(LockType lockType, String name, String [] keys) {
LockInfoHandle lockInfoHandle = lockInfoHandleFactory.getLockInfoHandle(LockInfoType.SERVICE_LOCK);
String lockName = lockInfoHandle.simpleGetLockName(name,keys);
ServiceLocker lock = serviceLockFactory.getLock(lockType);
return lock.getLock(lockName);
}
/**
* 获得锁
* @param lockType 锁类型
* @param lockName 锁名
*
* */
public RLock getLock(LockType lockType, String lockName) {
ServiceLocker lock = serviceLockFactory.getLock(lockType);
return lock.getLock(lockName);
}
}execute加锁方法
此方法的加锁逻辑和切面的大致相同
java
public void execute(LockType lockType,TaskRun taskRun,String name,String [] keys,long waitTime) {
//获取锁的名字解析处理器
LockInfoHandle lockInfoHandle = lockInfoHandleFactory.getLockInfoHandle(LockInfoType.SERVICE_LOCK);
//拼接锁的名字 LOCK:${name}:${key}
String lockName = lockInfoHandle.simpleGetLockName(name,keys);
//获得具体的锁类型
ServiceLocker lock = serviceLockFactory.getLock(lockType);
//进行加锁
boolean result = lock.tryLock(lockName, TimeUnit.SECONDS, waitTime);
//如果加锁成功
if (result) {
try {
//执行业务逻辑
taskRun.run();
}finally {
//解锁
lock.unlock(lockName);
}
}else {
//默认处理,快速失败
LockTimeOutStrategy.FAIL.handler(lockName);
}
}TaskRun是要进行加锁的逻辑
java
@FunctionalInterface
public interface TaskRun {
/**
* 执行任务
* */
void run();
}getLock加锁方法
这种加锁的方式和jdk中的Lock加锁方式相同,根据锁的类型和锁的名字以及锁的键值来获得锁的实例,然后用这个锁的实例来进行加锁和解锁的操作
java
/**
* 获得锁
* @param lockType 锁类型
* @param name 锁的业务名
* @param keys 锁的标识
*
* */
public RLock getLock(LockType lockType, String name, String [] keys) {
LockInfoHandle lockInfoHandle = lockInfoHandleFactory.getLockInfoHandle(LockInfoType.SERVICE_LOCK);
String lockName = lockInfoHandle.simpleGetLockName(name,keys);
ServiceLocker lock = serviceLockFactory.getLock(lockType);
return lock.getLock(lockName);
}
/**
* 获得锁
* @param lockType 锁类型
* @param lockName 锁名
*
* */
public RLock getLock(LockType lockType, String lockName) {
ServiceLocker lock = serviceLockFactory.getLock(lockType);
return lock.getLock(lockName);
}示例1
这种锁是使用命令模式加锁,加锁逻辑包装成TaskRun接口,传入execute方法,类似于线程池的提交
java
public void testLock(String name,long id){
serviceLockTool.execute(() -> updateData(name,id),LOCK_DATA, new String[]{String.valueOf(id)});
}
public void updateData(String name,long id){
//模拟修改数据
}示例2
java
public void testLock(String name,long id){
RLock lock = serviceLockTool.getLock(LockType.Reentrant, LOCK_DATA, new String[]{String.valueOf(id)});
lock.lock();
try {
updateData(name,id);
}finally {
lock.unlock();
}
}
public void updateData(String name,long id){
//模拟修改数据
}更新: 2025-10-13 11:51:17
原文: https://www.yuque.com/u22210564/ykdrdh/han0536p708u6thw