利用Redis实现单例锁自定义注解

springboot整合redis 都是老套玩法了,不再赘述记录

一、创建自定义注解,此自定义注解适用范围设定为method

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TaskRedisLock {

    /**
     * 锁一级锁名, 应用名,可能多个应用公用同一个redis链接信息,为了保证key唯一添加的一级拼接KEY
     * @return
     */
    String appKey() default "appName";

    /**
     * redis 锁key对应value值
     * @return
     */
    String value() default "";

    /**
     * 最大允许的锁定超时时间,在此阶段因为服务卡死等原因造成无法释放时,进行自动释放。
     * 单位为秒
     * @return
     */
    long maxLockTime() default 300;
}

二、利用spring切面方法执行前后进行redis加锁判断和执行后移除锁

/**
 * @Description: 自定义注解 redis锁操作
 * @Author 楚长川
 */
@Aspect
@Component
@Slf4j
public class AnnotationAspect {

    @Autowired
    private RedisTemplate redisTemplate;

	// Arround 内 annotation的值为自定义注解的全类名
    @Around("@annotation(com.systerm.TaskRedisLock)")
    public Object TaskLockExistQuery(ProceedingJoinPoint proceedingJoinPoint) {
        // 切面获取注解锁的和注解方法相关信息添加到redisKey中
        Method m=getMethod(proceedingJoinPoint,TaskRedisLock.class);
        TaskRedisLock taskRedisLock=m.getAnnotation(TaskRedisLock.class);
        String redisMethodKey = getRedisSecondKey(proceedingJoinPoint);
        // redis 锁设置-这里set操作
        boolean redisLock = redisTemplate.setIfAbsent(taskRedisLock.appKey().concat(-).concat(redisMethodKey)
                ,taskRedisLock.value(),taskRedisLock.maxLockTime()*1000);
        if (!redisLock) {
            String redisKey = String.format("redisKey:%s-%s is exist",taskRedisLock.appKey(),redisMethodKey )
            log.warn(redisKey);
            throw new RuntimeException(redisKey );
        }

        Object returnObj=null;
        try{
            // 执行实际业务方法
            returnObj= proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
        } catch(Exception e){
            log.error("task lock run:[exception]",e);
        } catch(Throwable e){
            log.error("task lock run:[throwable]",e);
        }
        //无论执行成功与否,都需要删除redis锁
        finally{
            MethodSignature ms = (MethodSignature)proceedingJoinPoint.getSignature();
            log.info("[success] run success: task check method:" + ms.getMethod().getName() +
                    " class:" + proceedingJoinPoint.getSignature().getDeclaringTypeName()+" ip:"+ IpUtil.getIp(), true);
            redisTemplate.delete(taskRedisLock.appKey().concat(-).concat(redisMethodKey));
        }

        return returnObj;
    }


    /**
     * 对实际业务method 的全类名和参数进行拼接,复杂key保证唯一性
     * @param proceedingJoinPoint
     * @return
     */
    private String getRedisSecondKey(ProceedingJoinPoint proceedingJoinPoint){
        MethodSignature ms = (MethodSignature)proceedingJoinPoint.getSignature();
        StringBuffer key=new StringBuffer();
        key.append(ms.getDeclaringTypeName());
        key.append("-");
        key.append(ms.getMethod().getName());

        /***
         * 参数信息拼接
         */
        if(proceedingJoinPoint.getArgs()!=null){

            for(Object obj:proceedingJoinPoint.getArgs()){
                if(obj!=null && !(obj instanceof Date)){
                    String str=obj.toString().replace(" ", "-");
                    key.append("-");
                    key.append(str);
                }
            }

        }
        return key.toString();
    }


    private Method getMethod(ProceedingJoinPoint proceedingJoinPoint, Class<? extends Annotation> clazz){
        MethodSignature ms = (MethodSignature) proceedingJoinPoint.getSignature();
        if (ms.getMethod().isAnnotationPresent(clazz)){
            return ms.getMethod();
        }
        Method m = ms.getMethod();
        try{
            Method m1 = proceedingJoinPoint.getTarget().getClass().getMethod(m.getName(), m.getParameterTypes());
            if (m1.isAnnotationPresent(clazz)){
                return m1;
            }
        }catch (Exception e){
            log.error("AnnotationAspect get annotation aspect method error",e);
        }
        throw new RuntimeException("adaptation annotations not found.");
    }
}

三、实际业务method使用

@Service
public class doServiceManagerImpl implements doServiceManager{
     
     @TaskRedisLock(appKey = "appName",value = "1",maxLockTime = 600)
     public void process(){
     	// todo
     }

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值