2019独角兽企业重金招聘Python工程师标准>>>

描述

  • 基于SpringEL表达式,动态配置
  • 基于切面,无缝切入
  • 支持获取锁失败时的行为,抛出异常还是继续等待,两种方式的锁,一种等待重试,一种直接退出

https://github.com/shawntime/shawn-common-utils/tree/master/src/main/java/com/shawntime/common/lock

使用方法

@RedisLockable(key = {"#in.activityId", "#in.userMobile"}, expiration = 120, isWaiting = true, retryCount = 2)
@Override
public PlaceOrderOut placeOrder(OrderIn in) {// ------
}

代码实现

package com.shawntime.common.lock;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** RUNTIME* 定义注解* 编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。* @author shma1664**/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RedisLockable {String prefix() default "";String[] key() default "";long expiration() default 120;boolean isWaiting() default false; //锁是否等待,默认为不等待int retryCount() default -1; // 锁等待重试次数,-1未不限制
}
package com.shawntime.common.lock;import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;import com.google.common.base.Joiner;
import com.shawntime.common.cache.redis.SpringRedisUtils;
import com.shawntime.common.common.spelkey.KeySpELAdviceSupport;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.aop.support.AopUtils;
import org.springframework.stereotype.Component;/*** Created by IDEA* User: mashaohua* Date: 2016-09-28 18:08* Desc:*/
@Aspect
@Component
public class RedisLockInterceptor extends KeySpELAdviceSupport {@Pointcut("@annotation(com.shawntime.common.lock.RedisLockable)")public void pointcut() {}@Around("pointcut()")public Object doAround(ProceedingJoinPoint point) throws Throwable {MethodSignature methodSignature = (MethodSignature) point.getSignature();Method targetMethod = AopUtils.getMostSpecificMethod(methodSignature.getMethod(), point.getTarget().getClass());String targetName = point.getTarget().getClass().getName();String methodName = point.getSignature().getName();Object target = point.getTarget();Object[] arguments = point.getArgs();RedisLockable redisLock = targetMethod.getAnnotation(RedisLockable.class);long expire = redisLock.expiration();String redisKey = getLockKey(redisLock, targetMethod, targetName, methodName, target, arguments);boolean isLock;if (redisLock.isWaiting()) {isLock = waitingLock(redisKey, expire, redisLock.retryCount());} else {isLock = noWaitingLock(redisKey, expire);}if (isLock) {long startTime = System.currentTimeMillis();try {return point.proceed();} finally {long parseTime = System.currentTimeMillis() - startTime;if (parseTime <= expire * 1000) {unLock(redisKey);}}} else {throw new RuntimeException("您的操作太频繁,请稍后再试");}}private String getLockKey(RedisLockable redisLock, Method targetMethod, String targetName, String methodName,Object target, Object[] arguments) {String[] keys = redisLock.key();String prefix = redisLock.prefix();StringBuilder sb = new StringBuilder("lock.");if (StringUtils.isEmpty(prefix)) {sb.append(targetName).append(".").append(methodName);} else {sb.append(prefix);}if (keys != null) {String keyStr = Joiner.on("+ '.' +").skipNulls().join(keys);SpELOperationContext context = getOperationContext(targetMethod, arguments, target, target.getClass());Object key = generateKey(keyStr, context);sb.append("#").append(key);}return sb.toString();}/*** 加锁** @param key    redis key* @param expire 过期时间,单位秒* @return true:加锁成功,false,加锁失败*/private boolean noWaitingLock(String key, long expire) {long value = System.currentTimeMillis() + expire * 1000;boolean status = SpringRedisUtils.setNX(key, value);if (status) {return true;}long oldExpireTime = SpringRedisUtils.get(key, Long.class);if (oldExpireTime < System.currentTimeMillis()) {//超时long newExpireTime = System.currentTimeMillis() + expire * 1000;Long currentExpireTime = SpringRedisUtils.getSet(key, newExpireTime, Long.class);if (currentExpireTime == null) {return true;}if (currentExpireTime.longValue() == oldExpireTime) {return true;}}return false;}/*** 等待锁** @param key    redis key* @param expire 过期时间,单位秒* @return true:加锁成功,false,加锁失败*/private boolean waitingLock(String key, long expire, int retryCount) {int count = 0;while (retryCount == -1 || count <= retryCount) {if (noWaitingLock(key, expire)) {return true;}try {TimeUnit.MILLISECONDS.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}count++;}return false;}private void unLock(String key) {SpringRedisUtils.delete(key);}}

转载于:https://my.oschina.net/shma1664/blog/826911

基于切面和注解的Redis分布式实现相关推荐

  1. 使用自定义注解实现Redis分布式锁

  2. spring boot 2.0 redis 分布式锁

    基于spring boot 2.0 redis 分布式锁,对于redis的一些基本配置及jar不做相关介绍,博客只是针对分布式锁使用. java代码: @Autowired private Redis ...

  3. @transaction使自定义注解失效_【完美】SpringBoot中使用注解来实现 Redis 分布式锁...

    一.业务背景 有些业务请求,属于耗时操作,需要加锁,防止后续的并发操作,同时对数据库的数据进行操作,需要避免对之前的业务造成影响. 二.分析流程 使用 Redis 作为分布式锁,将锁的状态放到 Red ...

  4. redis分布式锁java代码_基于redis实现分布式锁

    " 在上一篇文章中介绍了动态配置定时任务,其中的原理跟spring 定时任务注解@Scheduled一样的,都是通过线程池和定义执行时间来控制.来思考一个问题,如果我们的定时任务在分布式微服 ...

  5. redis分布式缓存php,基于redis分布式缓存实现

    第一:Redis 是什么? Redis是基于内存.可持久化的日志型.Key-Value数据库 高性能存储系统,并提供多种语言的API. 第二:出现背景数据结构(Data Structure)需求越来越 ...

  6. B2C商城项目源码,基于Java开发的高可用分布式B2C商城系统,Java+Spring MVC+Dubbo+Zookeeper+MySQL+Redis+FastDFS+Nginx+Solr

    目录 前言 B2C商城-AIYOU 一.项目总体架构 二.系统软硬件设施总体规划 1.系统服务规划 2.应用服务规划 3.应用系统域名规划 三.系统运行环境构建 四.项目数据库创建 五.项目拉取 六. ...

  7. Java版基于Redis分布式锁的实现方式

    一.什么是分布式锁? 要介绍分布式锁,首先要提到分布式锁相对应的线程锁和进程锁, 线程锁:组要是给方法.代码块加锁,当方法或者代码块使用锁时,在同一时刻只有一个线程可以执行该方法或者代码块,线程锁只在 ...

  8. 京东秒杀系统模块的Redis分布式锁深度剖析,没给你讲明白你打我

    1|0背景 目前开发过程中,按照公司规范,需要依赖框架中的缓存组件.不得不说,做组件的大牛对CRUD操作的封装,连接池.缓存路由.缓存安全性的管控都处理的无可挑剔.但是有一个小问题,该组件没有对分布式 ...

  9. Redis分布式锁实战

    背景 目前开发过程中,按照公司规范,需要依赖框架中的缓存组件.不得不说,做组件的大牛对CRUD操作的封装,连接池.缓存路由.缓存安全性的管控都处理的无可挑剔.但是有一个小问题,该组件没有对分布式锁做实 ...

最新文章

  1. Linux(Windows)下如何改变网卡的LinkSpeed工作模式
  2. SAP S/4HANA生产订单创建时使用的工厂数据是从什么地方带出来的
  3. java 将图片转成二进制文件bin_java 问题:怎样把一个bin二进制图片文件用java代码打开?求解!...
  4. Android-JSNative交互的几种可行性方案H5白屏问题解决方式
  5. python zlib字符串压缩
  6. Linux文件去掉^M
  7. 一文弄懂特征缩放(归一化/正则化)
  8. mysql sqlyog中文乱码_sqlyog 查询中文乱码
  9. 一篇文告诉你各行业视频监控录像的要求,看看你是否达标
  10. c语言程序设计杨明莉刘磊答案,清华大学出版社-图书详情-《C/C++程序设计基础与实践教程(第2版)》...
  11. 如何找回删除的文件?数据恢复,看这几个方法
  12. FLV合并开源代码flvmerge分析
  13. ajax用户登录注册
  14. spring mybatis 多数据源配置 jeesite 多数据源配置
  15. 使用zlib对字符串进行压缩
  16. 红帽考试资料_冰山一角
  17. vue3 props 声明默认值
  18. Netty处理TCP半包和粘包问题
  19. python快速实现2048小游戏
  20. 样本均值和样本方差的无偏性证明、正态分布样本方差的方差

热门文章

  1. java Windows7 下环境变量设置
  2. PARAMETER FILE研究
  3. SQLite管理工具绿色
  4. STL中的lower_bound() 和 upper_bound()
  5. [推荐]Silverlight 2 开发者海报
  6. Winform/WPF实例中的相互操作
  7. php libev pthreads,libuv 与 libev 的对比
  8. 计算机基础知识_2020年河北省高职单招计算机基础知识和实践技能培训
  9. es创建索引设置字段不分词_ES的使用笔记
  10. python爬图片_网络爬虫经验:反爬和反反爬