SpringBoot実装分散ロック(Spring integration+redis)


SpringBoot実装分散ロック(Spring integration+redis)
一、redisインストール
docker-composeを使用してインストールするために必要なredis環境
version: '3'
services:
  redis:
    image: redis	# redis  
    container_name: my_redis
    command: redis-server --requirepass 123456 	#        redis    
    ports:
      - "6379:6379"
    volumes:
      - ./data:/data
  phpredisadmin: 		# redis web     
    environment:
      - ADMIN_USER=admin	#   
      - ADMIN_PASS=admin		#  
      - REDIS_1_HOST=redis	#redis  
      - REDIS_1_PORT=6379	#redis  
      - REDIS_1_AUTH=123456	#redis  
    image: 172.26.206.220/library/phpredisadmin:1.0
    depends_on:
      - redis
    links:
      - redis
    ports:
      - "10001:80"


二、プロジェクトのpom.xml加入依存
1)Spring integration依存

	org.springframework.boot
	spring-boot-starter-integration


2)spring integration redis依存

	org.springframework.integration
	spring-integration-redis


3)spring data redis依存

    org.springframework.boot
    spring-boot-starter-data-redis


application.yml構成の追加
spring:
  redis:
    port: 6379
    host: ***.***.***.***
    password: 123456

RedisLockRegistry構成
package com.lzx.demo.configuration;

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;

/**
 *   :   
 *
 * @Auther: lzx
 * @Date: 2019/6/17 15:06
 */
@Configuration
public class RedisLockConfiguration {

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

}

三、コードの中で分布式ロックを使う
1)カスタムロック注記LzxLockDistributed
package com.lzx.demo.annotation;

import java.lang.annotation.*;

/**
 *   :       
 *
 * @Auther: lzx
 * @Date: 2019/6/17 16:24
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LzxLockDistributed {

    String value() default "";

    int time() default 30;
}


2)aopはロックの取得と解放を実現する
package com.lzx.demo.aop;

import com.lzx.demo.annotation.LzxLockDistributed;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.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.integration.redis.util.RedisLockRegistry;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

/**
 *   :    LzxLockDistributed     Aop
 *
 * @Auther: lzx
 * @Date: 2019/6/18 10:56
 */
@Component
@Aspect
@Slf4j
public class MethodLockAop {

    private WebApplicationContext webApplicationContext;

    public MethodLockAop(WebApplicationContext webApplicationContext) {
        this.webApplicationContext = webApplicationContext;
    }

    @Pointcut("@annotation(com.lzx.demo.annotation.LzxLockDistributed)")
    private void apiAop(){

    }

    @Around("apiAop()")
    public Object aroundApi(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        LzxLockDistributed lzxLockDistributed = method.getAnnotation(LzxLockDistributed.class);
        String localRegistry = lzxLockDistributed.value();
        if(StringUtils.isBlank(localRegistry)){
            throw new RuntimeException("   Registry beann   ");
        }

        RedisLockRegistry redisLockRegistry = (RedisLockRegistry) webApplicationContext.getBean(lzxLockDistributed.value());

        Lock lock = redisLockRegistry.obtain(signature.getName());
        boolean b = false;
        for(int i =0 ; i<3;i++){
            b = lock.tryLock(lzxLockDistributed.time(), TimeUnit.SECONDS);
            if(b){
                break;
            }else {
                continue;
            }
        }
        log.info("   ====="+b);
        Object proceed = null;
        try{
            proceed = point.proceed();
        }catch (Exception e){
            throw e;
        }finally {
            try{
                lock.unlock();
            }catch (Exception e){
                log.error(e.getMessage(),e);
            }
        }


        return proceed;

    }

}


3)注釈による方法のロック
    @LzxLockDistributed(value = "redisLockRegistry",time = 60)
    public String redisLockTest() throws InterruptedException {
        if(inventory >= 5){
            return "      ~~~";
        }
        String s = strArr[inventory];
        Thread.sleep(10*1000);
        inventory++;
        return s;

    }