用Redisson实现分布式锁

学无止境,厚积薄发

一、pom.xml文件中引入redisson依赖包


    org.redisson
    redisson
    2.2.13

二、在resources/conf下创建redis.properties文件
redis.host=127.0.0.1
redis.port=6379
redis.password=123456
redis.database=3
redis.timeout=1800
redis.pool.maxTotal=1000
redis.pool.maxIdle=200
redis.pool.maxWaitMillis=1000
redis.pool.testOnBorrow=false
三、自定义分布式注解RedisLock
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;

/**
 * 分布式锁的注解, 通过指定key作为分布式锁的key
 * 
 * @author chenxj
 *
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
@Documented
public @interface RedisLock {

    /**
     * 分布式锁的key
     * @return
     */
    String key();

    /**
     * 分布式锁用的业务场景id
     * @return
     */
    String biz() default "";

    /**
     * 过期时间, 默认是5秒 
     * 单位是秒
     * @return
     */
    int keepMills() default 120;

    /**
     * 没有获取到锁时,等待时间
     * 单位是秒     
     * @return     
     */
    long maxSleepMills() default 120;
    
    /**
     * 单位默认秒
     * @return
     */
    TimeUnit timeUnit() default TimeUnit.SECONDS;
}
四、创建Redis client的辅助工具类
import org.redisson.Config;
import org.redisson.Redisson;
import org.redisson.RedissonClient;
import org.redisson.core.RAtomicLong;
import org.redisson.core.RBlockingQueue;
import org.redisson.core.RBucket;
import org.redisson.core.RCountDownLatch;
import org.redisson.core.RDeque;
import org.redisson.core.RList;
import org.redisson.core.RLock;
import org.redisson.core.RMap;
import org.redisson.core.RQueue;
import org.redisson.core.RSet;
import org.redisson.core.RSortedSet;
import org.redisson.core.RTopic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Redis client的辅助工具类
 * 用于连接Redis服务器 创建不同的Redis Server对应的客户端对象
 *
 * @author chenxj
 */
public class RedisUtils {

    private static Logger logger = LoggerFactory.getLogger(RedisUtils.class);

    private static RedisUtils redisUtils;

    private RedisUtils() {
    }

    /**
     * 提供单例模式
     *
     * @return
     */
    public static RedisUtils getInstance() {
        if (redisUtils == null)
            synchronized (RedisUtils.class) {
                if (redisUtils == null) redisUtils = new RedisUtils();
            }
        return redisUtils;
    }


    /**
     * 使用config创建Redisson
     * Redisson是用于连接Redis Server的基础类
     *
     * @param config
     * @return
     */
    public RedissonClient getRedisson(Config config) {
        RedissonClient redisson = Redisson.create(config);
        logger.info("成功连接Redis Server");
        return redisson;
    }

    /**
     * 使用ip地址和端口创建Redisson
     *
     * @param ip
     * @param port
     * @return
     */
    public RedissonClient getRedisson(String ip, String port) {
        Config config = new Config();
        config.useSingleServer().setAddress(ip + ":" + port);
        RedissonClient redisson = Redisson.create(config);
        logger.info("成功连接Redis Server" + "\t" + "连接" + ip + ":" + port + "服务器");
        return redisson;
    }

    /**
     * 关闭Redisson客户端连接
     *
     * @param redisson
     */
    public void closeRedisson(RedissonClient redisson) {
        redisson.shutdown();
        logger.info("成功关闭Redis Client连接");
    }

    /**
     * 获取字符串对象
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public  RBucket getRBucket(RedissonClient redisson, String objectName) {
        RBucket bucket = redisson.getBucket(objectName);
        return bucket;
    }

    /**
     * 获取Map对象
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public  RMap getRMap(RedissonClient redisson, String objectName) {
        RMap map = redisson.getMap(objectName);
        return map;
    }

    /**
     * 获取有序集合
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public  RSortedSet getRSortedSet(RedissonClient redisson, String objectName) {
        RSortedSet sortedSet = redisson.getSortedSet(objectName);
        return sortedSet;
    }

    /**
     * 获取集合
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public  RSet getRSet(RedissonClient redisson, String objectName) {
        RSet rSet = redisson.getSet(objectName);
        return rSet;
    }

    /**
     * 获取列表
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public  RList getRList(RedissonClient redisson, String objectName) {
        RList rList = redisson.getList(objectName);
        return rList;
    }

    /**
     * 获取队列
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public  RQueue getRQueue(RedissonClient redisson, String objectName) {
        RQueue rQueue = redisson.getQueue(objectName);
        return rQueue;
    }

    /**
     * 获取双端队列
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public  RDeque getRDeque(RedissonClient redisson, String objectName) {
        RDeque rDeque = redisson.getDeque(objectName);
        return rDeque;
    }

    /**
     * 此方法不可用在Redisson 1.2 中
     * 在1.2.2版本中 可用
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public  RBlockingQueue getRBlockingQueue(RedissonClient redisson, String objectName) {
        RBlockingQueue rb = redisson.getBlockingQueue(objectName);
        return rb;
    }

    /**
     * 获取锁
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public RLock getRLock(RedissonClient redisson, String objectName) {
        RLock rLock = redisson.getLock(objectName);
        return rLock;
    }

    /**
     * 获取原子数
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public RAtomicLong getRAtomicLong(RedissonClient redisson, String objectName) {
        RAtomicLong rAtomicLong = redisson.getAtomicLong(objectName);
        return rAtomicLong;
    }

    /**
     * 获取记数锁
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public RCountDownLatch getRCountDownLatch(RedissonClient redisson, String objectName) {
        RCountDownLatch rCountDownLatch = redisson.getCountDownLatch(objectName);
        return rCountDownLatch;
    }

    /**
     * 获取消息的Topic
     *
     * @param redisson
     * @param objectName
     * @return
     */
    public  RTopic getRTopic(RedissonClient redisson, String objectName) {
        RTopic rTopic = redisson.getTopic(objectName);
        return rTopic;
    }

}
五、创建分布式锁拦截器RedisLockInterceptor
import java.lang.reflect.Method;

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.redisson.Config;
import org.redisson.RedissonClient;
import org.redisson.SingleServerConfig;
import org.redisson.core.RLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import com.chanxj.common.annotation.RedisLock;
import com.chanxj.common.util.RedisUtils;

/**
 * redis锁拦截器实现
 * 
 * @author chenxj
 *
 */
@Aspect
@Component
public class RedisLockInterceptor {
    private static Logger logger = LoggerFactory.getLogger(RedisLockInterceptor.class);
    
    /**
     * redis地址
     */
    @Value("${redis.host}:${redis.port}") 
    private String address;
    
    /**
     * redis密码
     */
    @Value("${redis.password}") 
    private String password;
    
    /**
     * 数据库编号
     */
    @Value("${redis.database}")
    private Integer database;
    
    /**
     * 超时
     */
    @Value("${redis.timeout}")
    private Integer timeout;
    
    @Bean
    public RedissonClient getRedissonClient(){
        //redisson配置
        Config config = new Config();
        SingleServerConfig singleSerververConfig = config.useSingleServer();
        singleSerververConfig.setAddress(address);
        singleSerververConfig.setPassword(password);
        singleSerververConfig.setDatabase(database);
        singleSerververConfig.setTimeout(timeout);
        //redisson客户端
        RedissonClient redissonClient = RedisUtils.getInstance().getRedisson(config);
        return redissonClient;
    }
    
    @Autowired
    private RedissonClient redissonClient;
    
    @Pointcut("@annotation(com.chanxj.common.annotation.RedisLock)")
    public void redisLockAspect() {
    }

    @Around("redisLockAspect()")
    public Object lockAroundAction(ProceedingJoinPoint point) {
        //获取锁
        RLock lock = null;
        Object object = null;
        logger.info("开始获取锁!");
        try {
            RedisLock redisLock = getRedisLockInfo(point);
            RedisUtils redisUtils = RedisUtils.getInstance();
            //获取锁键值
            String lockKey = getRedisKey(point, redisLock);
            lock = redisUtils.getRLock(redissonClient, lockKey);
            if(lock != null){
                //第一个参数代表等待时间,第二是代表超过时间释放锁,第三个代表设置的时间制
                Boolean status = lock.tryLock(redisLock.maxSleepMills(), redisLock.keepMills(), redisLock.timeUnit());
                if(status){
                    object = point.proceed();
                }
            }
        } catch (Throwable e) {
            logger.error("Redis锁操作异常{}", e);
        } finally {
            if (lock != null) {
                lock.unlock();
            }
        }
        logger.info("结束获取锁!");
        
        return object;
    }

    /**
     * 获取注解信息
     * @param point
     * @return
     */
    private RedisLock getRedisLockInfo(ProceedingJoinPoint point) {
        try {
            MethodSignature methodSignature = (MethodSignature) point.getSignature();
            Method method = methodSignature.getMethod();
            return method.getAnnotation(RedisLock.class);
        } catch (Exception e) {
            logger.info(e.getMessage());
        }
        return null;
    }
    
    /**
     * 获取redis key值
     * @param redisLock
     * @return
     */
    private String getRedisKey(ProceedingJoinPoint point, RedisLock redisLock){
        String keyEL = redisLock.key();
        //1、创建解析器
        ExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression(keyEL);
        //2、设置解析上下文(有哪些占位符,以及每种占位符的值)
        EvaluationContext context = new StandardEvaluationContext(); //参数
        //3、真实参数名(运行时获取参数名:arg0 arg1 arg2)
        Object[] args = point.getArgs();
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        String[] parameterNames = methodSignature.getParameterNames();
        for (int i = 0; i < parameterNames.length; i++) {
            context.setVariable(parameterNames[i], args[i]);
        }
        //4、解析
        String key = expression.getValue(context).toString();
        return key;
    }

}
六、测试
@RedisLock(key="'test_' + #id")
public HashMap test(Integer id) {
    //TODO 做一些不可描述的事
    
}

欢迎关注我的公众号:Java软件编程(javarjbc)

你可能感兴趣的:(用Redisson实现分布式锁)