SpringBoot+Zookeeper+Curator+SpEL+AOP实现优雅无侵入分布式锁

SpringBoot+Zookeeper+Curator+SpEL+AOP实现优雅无侵入分布式锁

    • 序言
    • maven依赖
    • 配置文件
    • 配置类
    • 分布式锁客户端
    • 分布式锁注解
    • 分布式锁切面类

序言

分布式锁在主流实现技术上主要有以下三种:

  • 基于redis实现,比如redis官方推荐的redisson
  • 基于数据库实现,比如借助unique key
  • 基于zookeeper,主要是临时文件路径+session

至于优劣可参考另外一篇博客。本篇博客演示的是zookeeper结合apache的curator实现分布式锁。

maven依赖

<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>4.2.0</version>
    <exclusions>
        <!-- 防止zookeeper版本冲突 -->
        <exclusion>
            <artifactId>zookeeper</artifactId>
            <groupId>org.apache.zookeeper</groupId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>4.2.0</version>
    <exclusions>
        <exclusion>
            <artifactId>zookeeper</artifactId>
            <groupId>org.apache.zookeeper</groupId>
        </exclusion>
    </exclusions>
</dependency>

配置文件

application.yml

zookeeper:
    servers: localhost:2181,localhost:2182 # 换成自己的环境
    lockPath: /lock/ # 指定分布式锁路径
    sessionTimeoutMs: 60000 # session超时时间
    connectionTimeoutMs: 5000 # 连接超时时间
    retryCount: 5 # 尝试获取锁最大重试次数
    elapsedTimeMs: 1000 # 重试间隔时间

配置类

@Data
@Component
@ConfigurationProperties(prefix = "zookeeper")
public class ZookeeperConfigurer {
     

    /** 尝试次数 */
    private int retryCount;

    /** 重试间隔时间 */
    private int elapsedTimeMs;

    /** session超时时间 */
    private int sessionTimeoutMs;

    /** 连接超时时间 */
    private int connectionTimeoutMs;

    /** zookeeper集群地址 */
    private String servers;

    /** zookeeper分布式锁跟路径 */
    private String lockPath;

}

分布式锁客户端

@Configuration
public class CuratorConfigurer {
     

    @Autowired
    private ZookeeperConfigurer zkConfigurer;

    @Bean(initMethod = "start", destroyMethod = "close")
    public CuratorFramework curatorFramework() {
     
        return CuratorFrameworkFactory.newClient(
                zkConfigurer.getServers(),
                zkConfigurer.getSessionTimeoutMs(),
                zkConfigurer.getConnectionTimeoutMs(),
                new RetryNTimes(zkConfigurer.getRetryCount(), zkConfigurer.getElapsedTimeMs()));
    }

}

分布式锁注解

/**
 * 

分布式锁注解

* @author [email protected] * @version 1.0.0 */ @Target({ ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DistributedLock { String name() ; }

分布式锁切面类

@Aspect
@Component
public class DistributedLockAspect {
     
 
    @Autowired
    private CuratorFramework curatorFramework;
 
    @Pointcut("@annotation(com.clickpaas.annotation.DistributedLock)")
    public void distributedLockAspect() {
     }
 
    @Around(value = "distributedLockAspect()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
     
    	// target class
        Class<?> targetClass = pjp.getTarget().getClass();
        // method name
        String methodName = pjp.getSignature().getName();
        // parameter types
        Class<?>[] parameterTypes = ((MethodSignature) pjp.getSignature()).getMethod().getParameterTypes();
        // method
        Method method = targetClass.getMethod(methodName, parameterTypes);
        // arguments
        Object[] arguments = pjp.getArgs();

        return lock(pjp, method, arguments);
    }
    
    private Object lock(ProceedingJoinPoint pjp, Method method, Object[] arguments) throws Throwable {
     
        DistributedLock annotation = method.getAnnotation(DistributedLock.class);
        String lockName = parseKey( annotation, method, arguments );

        InterProcessMutex mutex = new InterProcessMutex(curatorFramework, zookeeperConfigurer.getLockPath() + lockName);
        if ( mutex.acquire(0, TimeUnit.SECONDS) ) {
     
            return pjp.proceed();
        }
        
        return null;
    }
    
    private String parseKey(DistributedLock annotation, Method method, Object[] args){
     
        LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
        String [] paraNameArr = u.getParameterNames(method);
        
        ExpressionParser parser = new SpelExpressionParser(); 
        StandardEvaluationContext context = new StandardEvaluationContext();
        
        for(int i=0; i<paraNameArr.length; ++i){
     
            context.setVariable(paraNameArr[i], args[i]);
        }
        
        String lockName = annotation.name();
        if(lockName.contains("#")) {
     
        	lockName = parser.parseExpression(lockName).getValue(context, String.class);
        }

        return lockName;
    }
    
    @AfterThrowing(value = "distributedLockAspect()", throwing="ex")
    public void afterThrowing(Throwable ex) {
     
        throw new RuntimeException(ex);
    }
    
}

你可能感兴趣的:(分布式,#,分布式锁,分布式,spring,boot,aop,zookeeper)