转载

基于注解的方式使用spring-integration-redis分布式锁

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface CacheLock {

  String prefix() default "";

//  int expire() default 5;

//  TimeUnit timeUnit() default TimeUnit.SECONDS;

  String delimiter() default ":";
}
复制代码
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface CacheParam {

  String name() default "";

  int order() default -1;
}
复制代码

二.定义切面类

package com.xxx.xx.common.aop;

import com.alibaba.excel.util.StringUtils;
import com.xxx.xx.common.annotation.CacheBody;
import com.xxx.xx.common.annotation.CacheLock;
import com.xxx.xx.common.annotation.CacheParam;
import com.xxx.xx.common.aop.dto.CacheParamDTO;
import com.xxx.xx.common.dto.Ret;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.locks.Lock;
import org.apache.commons.lang3.ArrayUtils;
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.CodeSignature;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.stereotype.Component;

/**
 * @Author: hlm
 * @Date: 2019/4/4 10:46
 */
@Aspect
@Component
public class CacheLockAop {

  @Autowired
  private RedisLockRegistry redisLockRegistry;

  @Pointcut("@annotation(cacheLock)")
  public void cacheLockPointCut(CacheLock cacheLock) {
  }

  @Around("cacheLockPointCut(cacheLock)")
  public Object around(ProceedingJoinPoint joinPoint, CacheLock cacheLock)
      throws Throwable {

    MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
    Method method = methodSignature.getMethod();
    if (StringUtils.isEmpty(cacheLock.prefix())) {
      throw new RuntimeException("key不能为空, 请在@CacheLock中定义prefix=%s");
    }

    CodeSignature codeSignature = (CodeSignature) joinPoint.getSignature();
    String[] parameterNames = codeSignature.getParameterNames();
    //获取方法入参,组装key
    List<CacheParamDTO> cacheParamDTOList = new ArrayList<>();
    Annotation[][] parameterAnnotations = method.getParameterAnnotations();
    for (Annotation[] parameterAnnotation : parameterAnnotations) {
      int paramIndex = ArrayUtils.indexOf(parameterAnnotations, parameterAnnotation);
      for (Annotation annotation : parameterAnnotation) {
        if (annotation instanceof CacheParam) {
          CacheParamDTO cacheParamDTO = new CacheParamDTO();
          if (StringUtils.isEmpty(((CacheParam) annotation).name())) {
            cacheParamDTO.setName(parameterNames[paramIndex]);
          } else {
            cacheParamDTO.setName(((CacheParam) annotation).name());
          }
          cacheParamDTO.setOrder(((CacheParam) annotation).order());
          cacheParamDTO.setValue(joinPoint.getArgs()[paramIndex].toString());
          cacheParamDTOList.add(cacheParamDTO);
        }
        if (annotation instanceof CacheBody) {
          Object obj = joinPoint.getArgs()[paramIndex];
          Class bodyClass = obj.getClass();
          Field[] fields = bodyClass.getDeclaredFields();
          for (Field field : fields) {
            if (field.isAnnotationPresent(CacheParam.class)) {
              Annotation fieldAnnotation = field.getAnnotation(CacheParam.class);
              field.setAccessible(true);
              CacheParamDTO cacheParamDTO = new CacheParamDTO();
              if (StringUtils.isEmpty(((CacheParam) fieldAnnotation).name())) {
                cacheParamDTO.setName(field.getName());
              } else {
                cacheParamDTO.setName(((CacheParam) fieldAnnotation).name());
              }
              cacheParamDTO.setOrder(((CacheParam) fieldAnnotation).order());
              cacheParamDTO.setValue((String) field.get(obj));
              cacheParamDTOList.add(cacheParamDTO);
            }
          }
        }
      }
    }
    StringBuilder builder = new StringBuilder();
    cacheParamDTOList.sort(Comparator.comparing(item -> item.getOrder()));
    for (CacheParamDTO cacheParamDTO : cacheParamDTOList) {
      builder.append(cacheLock.delimiter())
          .append(cacheParamDTO.getName())
          .append(cacheLock.delimiter())
          .append(cacheParamDTO.getValue());
    }
    final String key = cacheLock.prefix() + builder.toString();
    
    //spring-integration对redis分布锁的支持,底层应该也是lua脚本的实现,可完美解决线程挂掉造成的死锁,以及执行时间过长锁释放掉,误删别人的锁
    Lock lock = redisLockRegistry.obtain(key);
    Boolean lockFlag = lock.tryLock();
    if (!lockFlag) {
      return new Ret<>("M4000", "系统繁忙,请重试");
    }
    Object object = null;
    try {
      object = joinPoint.proceed();
    } finally {
      lock.unlock();
    }
    return object;
  }
}
复制代码

三.配置文件

package com.xxx.xx.common.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.integration.redis.util.RedisLockRegistry;

/**
 * @Author: hlm
 * @Date: 2019/4/8 8:59
 */
@Configuration
public class RedisLockConfiguration {

  @Bean
  public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) {
    return new RedisLockRegistry(redisConnectionFactory, "locks");
  }
}

复制代码

四.maven依赖

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-integration</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.integration</groupId>
      <artifactId>spring-integration-redis</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
      <version>2.0.4.RELEASE</version>
    </dependency>
复制代码

本人第一次发帖,望大佬给出意见,在下会十分感谢的

原文  https://juejin.im/post/5cab0f69518825583c3dd331
正文到此结束
Loading...