优雅的实现分布式锁控制-自定义注解方式
2020-04-29 本文已影响0人
yufw
自定义注解实现分布式锁实现
分布式锁的实现基于redisson
背景
很久很久以前,我们的架构都是单体架构,项目也只会部署到一台服务器,基于JVM的 java 同步工具(如ReentrantLcok或synchronized)完全可以保证我们的业务的 原子性;随着微服务,分布式的出现,一个项目会部署到多台服务器(多个JVM),这时候多个服务之间的一系列操作要保证原子性,基于JVM的 java 同步工具(如ReentrantLcok或synchronized)就无能为力了,这时候需要一个针对整个项目(包含所有服务)的一个全局锁来控制业务,这时候分布式锁就应运而生。
分布式锁的 注意事项
- 加锁必须设置过期时间(避免死锁)
- 加锁操作必须和设置 过期时间 是原子性操作
并发操作下 导致加过期时间失败问题(某个线程执行完枷锁操作 未加过期时间 报错终止) - 过期时间 必须保证业务操作 结束
开始子线程监控 未执行结束 续命(加过期时间) - 必须保证 谁加锁 谁解锁
防止高并发下 锁失效问题
java 源码
@RestController
public class RedissonLock {
// 分布式锁的 注意事项
// 1. 加锁必须设置过期时间
// (避免死锁)
// 2. 加锁操作必须和设置 过期时间 是原子性操作
// 并发操作下 导致加过期时间失败问题(某个线程执行完枷锁操作 未加过期时间 报错终止)
// 3. 过期时间 必须保证业务操作 结束
// 开始子线程监控 未执行结束 续命(加过期时间)
// 4. 必须保证 谁加锁 谁解锁
// 防止高并发下 锁失效问题
static int r = 0;
@Autowired
private RedissonClient redissonClient;
@GetMapping("/testLock")
public int testRedissonLock(@RequestParam boolean isLock) throws InterruptedException {
RLock rLock = null;
int result = 0;
if(isLock){
try{// 获取锁
rLock = redissonClient.getLock("test1");
// 上锁
rLock.lock(12, TimeUnit.SECONDS);
result = dobusiness();
}
finally {
// 解锁
rLock.unlock();
}
} else {
result = dobusiness();
}
return result;
}
private int dobusiness() throws InterruptedException {
++r;
TimeUnit.SECONDS.sleep(1);
System.out.println(r);
return r;
}
转自我的 另一篇博客 https://blog.csdn.net/qq_41692766/article/details/105770758
使用自定义注解方式实现分布式锁控制
主要使用技术:
- 自定义注解
- 切面编程
1. 自定义注解的使用
请参考 我的另一篇博客:https://blog.csdn.net/qq_41692766/article/details/105821144(此处不赘述)
2. 面向切面编程
请参考 我的另一篇博客:https://blog.csdn.net/qq_41692766/article/details/105821218(此处不赘述)
进入正题
准备工作完成,我们直奔主题:
-
redisson 服务接口
package com.beauty.beautybase.service; import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit; /** * description Redisson 服务类 * * @author yufw * date 2020/4/27 16:40 */ public interface RedissonService { /** * 无指定时间 加锁 */ void lock(String name); /** * 指定时间 加锁 * * @param leaseTime * @param unit */ void lock(String name, long leaseTime, TimeUnit unit); boolean tryLock(String name); boolean tryLock(String name, long time, TimeUnit unit) throws InterruptedException; boolean isLocked(String name); void unlock(String name); }
-
接口实现
package com.beauty.beautybase.service.Impl; import com.beauty.beautybase.service.RedissonService; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit; /** * description * * @author yufw * date 2020/4/27 16:43 */ @Service public class RedissonServiceImpl implements RedissonService { @Autowired private RedissonClient redissonClient; private RLock getLock(String name) { RLock lock = redissonClient.getLock(name); return lock; } /** * 无指定时间 加锁 */ @Override public void lock(String name) { getLock(name).lock(); } /** * 指定时间 加锁 * * @param leaseTime * @param unit */ @Override public void lock(String name, long leaseTime, TimeUnit unit) { } @Override public boolean tryLock(String name) { return false; } @Override public boolean tryLock(String name, long time, TimeUnit unit) throws InterruptedException { return false; } @Override public boolean isLocked(String name) { return false; } @Override public void unlock(String name) { getLock(name).unlock(); } }
-
自定义注解
package com.beauty.beautybase.annotion; import java.lang.annotation.*; import java.util.concurrent.TimeUnit; @Target({ElementType.PARAMETER, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DistributeLock { /** * 锁类型 * * @return */ LockType type() default LockType.LOCK; /** * 分布式锁 名称 * * @return */ String name() default "lock"; long leaseTime() default -1; TimeUnit unit() default TimeUnit.SECONDS; }
-
注解逻辑
package com.beauty.beautybase.AOP; import com.beauty.beautybase.annotion.DistributeLock; import com.beauty.beautybase.annotion.LockType; import com.beauty.beautybase.service.RedissonService; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * description 分布式锁自定义注解 切面 * * @author yufw * date 2020/4/27 13:11 */ @Aspect @Component public class DistributeLockAop { @Autowired RedissonService redissonService; /** * 切入点 */ @Pointcut("@annotation(com.beauty.beautybase.annotion.DistributeLock)") public void doBusiness() { } /** * 前事件 * * @param joinPoint */ @Before("doBusiness()") public void doBefore(JoinPoint joinPoint) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); //获取执行方法 Method method = signature.getMethod(); // 获取注解信息 DistributeLock distributeLock = method.getAnnotation(DistributeLock.class); if (null != distributeLock) { //获取注解参数值 String lockName = distributeLock.name(); LockType type = distributeLock.type(); if (type == LockType.LOCK) { redissonService.lock(lockName); System.out.println("加锁成功"); } } } /** * 后事件 * * @param joinPoint */ @After("doBusiness()") public void doAfter(JoinPoint joinPoint) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); //获取执行方法 Method method = signature.getMethod(); // 获取注解信息 DistributeLock distributeLock = method.getAnnotation(DistributeLock.class); //获取执行方法名 String methodName = method.getName(); //获取方法传递的参数 Object[] args = joinPoint.getArgs(); if (null != distributeLock) { //获取注解参数值 String lockName = distributeLock.name(); if (null != distributeLock) { redissonService.unlock(lockName); System.out.println("解锁成功"); } } } }
-
测试接口编写
package com.beauty.beautybase.controller; import com.beauty.beautybase.annotion.DistributeLock; import com.beauty.beautybase.annotion.LockType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.TimeUnit; /** * description * * @author yufw * date 2020/4/28 9:42 */ @RestController @RequestMapping("/commonBase") public class DistributeLockController { @DistributeLock(type = LockType.LOCK, name = "lock") @GetMapping("/lock") public void testLock() throws Exception { System.out.println("test_lock"); System.out.println("需要加分布式锁的业务逻辑"); // 此处测试 如果处理 业务逻辑 报错 是否会 解锁(防止死锁) //throw new Exception("业务报错"); } @GetMapping("/lockTimed") public void testLockTimed() { System.out.println("test_lockTimed"); } @GetMapping("/tryLock") public void testTryLock() { } @GetMapping("tryLockTimed") public void testTryLockTimed(@RequestParam int time, @RequestParam TimeUnit unit) { } }
备注:此功能会持续优化,暂简单实现
个人水平有限,如有问题,请各路大神指教留言,评论区讨论,虚心接纳
如果觉得有帮助,请点赞收藏,谢谢