[框架系列]-[通用lock框架]集成及具体配置使用

目录

一:框架集成

1.添加pom依赖

2.开启lock配置

二:配置详细介绍

1.配置清单

2.具体配置介绍

(1)implementer

(2)type

(3)transactionStrategy

(4)lockFailStrategy

(5)lockExceptionStrategy

(6)releaseTimeoutStrategy

三:CUSTOMER的SPI扩展示例

1.SPI扩展点

2.使用示例

四:代码示例

1.代码方式

2:注解方式示例

(1).方法头部同时存在@Transactional及@Lock时

(2).@LockKey的使用

(3).快捷注解的使用

4().自定义快速失败时,抛出的异常类型及异常信息(可单独设置)

(5).定制上锁失败策略


一:框架集成

1.添加pom依赖

<dependency>

   <groupId>com.ty</groupId>

   <artifactId>ty-framework-lock-starter</artifactId>

   <version>0.2.9</version>

</dependency>

2.开启lock配置

目前分布式锁仅支持redis实现

application.yml示例:

application:

  lock:

    enable: true

spring:

  redis:

    database: 3

    cluster:

      nodes: 192.168.xx.xxx:6479,192.168.xx.xxx:6479,192.168.xx.xxx:6479

    password: 12345678

application.properties示例:

application.lock.enable=true

#redis集群版配置示例,其他版本配置具体见Spring redis相关配置

spring.redis.database=3

spring.redis.cluster.nodes=192.168.xx.xxx:6479,192.168.xx.xxx:6479,192.168.xx.xxx:6479

spring.redis.password=12345678

如遇到集成问题,可联系@苏友良

二:配置详细介绍

1.配置清单

配置名

配置简介

默认值

作用域

其他

enable

是否开启

Boolean.FALSE

全局

使用需开启此配置

implementer

lock厂商实现类型

LockImplementer.REDIS

全局及注解

redis实现

type

lock 的类型

LockType.Reentrant

全局及注解

keys

自定义业务key(支持SpingEL)

注解

系统会按照${name}:${key1}:...:${keyN}:${@LockKey1}:...:${@LockKeyN}的方式拼接,作为lock的key

特殊的:当name,keys以及注解@LockKey都为空时,系统默认使用方法的全限定类名作为key(不推荐使用此方式)

name

锁的名称

注解

系统会按照${name}:${key1}:...:${keyN}:${@LockKey1}:...:${@LockKeyN}的方式拼接,作为lock的key

特殊的:当name,keys以及注解@LockKey都为空时,系统默认使用方法的全限定类名作为key(不推荐使用此方式)

supportTransaction

是否支持上下文感知

Boolean.TRUE

全局及注解

withLocalCache

是否支持本地lock二级缓存

Boolean.FALSE

全局及注解

transactionStrategy

仅开启supportTransaction生效

LockTransactionStrategy.WARMING

全局

打warm日志

waitTime

等待时间

2s

全局及注解

leaseTime

等待时间

60s

全局及注解

此参数在Lock官方定义中不生效,可通过自定义LockAdapter使用该参数。redis实现中默认此参数不生效(自动续期机制),如方言需使用此参数参考:cn.techwolf.blue.usl.framework.lock.factory.support.RedissonLockAdapterFactory

lockFailStrategy

加锁失败的处理策略

FailOnLockStrategy.FAIL_FAST

全局及注解

快速失败

exceptionOnLockStrategy

加锁异常的处理策略

ExceptionOnLockStrategy.THROW_EXCEPTION

全局及注解

抛出异常

releaseTimeoutStrategy

释放锁时异常的处理策略

ReleaseTimeoutStrategy.FAIL_FAST

全局及注解

快速失败

exceptionClass

获取锁失败时,报错的异常类型

LockException

全局及注解

获取锁失败时,报错的异常类型
1.仅当LockFailStrategy.FAIL_FAST或者ReleaseTimeoutStrategy.FAIL_FAST 生效 此处设置二者都会生效
2.优先级:注解exceptionClass>lockConfig exceptionClass>系统默认
3.示例:cn.techwolf.blue.usl.framework.common.exception.FrameworkException
4.注意:必须是RuntimeException的子类

exceptionMsg

获取锁失败时,报错的错误信息

Failed to acquire Lock(%s) with timeout(%d ms)

全局及注解

仅当LockFailStrategy.FAIL_FAST或者ReleaseTimeoutStrategy.FAIL_FAST生效此处设置二者都会生效
优先级:注解exceptionClass>lockConfig exceptionClass>系统默认

customLockFailStrategy 定制的加锁失败的处理策略 注解 用户指定,定义的方法参数需要和注解所在的方法参数保持一致

此方式与lockFailStrategy中的CUSTOM不同点在于:此方式可对方法具体参数做定制化的处理策略,
后者更适合做全局的默认处理
customReleaseTimeout
Strategy
定制的释放锁时异常的处理策略 注解

用户指定,定义的方法参数需要和注解所在的方法参数保持一致

此方式与releaseTimeoutStrategy中的CUSTOM不同点在于:此方式可对方法具体参数做定制化的处理策略,后者更适合做全局的默认处理

注解配置优先级大于全局配置。仅当注解没有配置才会使用全局配置

2.具体配置介绍
(1)implementer

提供的厂商实现:

  • JVM 本地JVM实现
  • REDIS redis实现 
  • ZOOKEEPER zookeeper实现
  • ETCD etcd实现
  • MYSQL mysql实现

具体见:cn.techwolf.blue.usl.framework.lock.config.LockConfig.LockImplementer

(2)type

lock厂商实现类型:

  • Reentrant 可重入锁

  • Fair 公平锁
  • Read 读锁
  • Write 写锁
  • Spin 自旋锁

具体见:cn.techwolf.blue.usl.framework.lock.enums.LockType

(3)transactionStrategy

当lock存在于事务上下文中的策略(仅开启supportTransaction生效):

  • WAARMING  打warming日志
  • FORBIDDEN 禁止,会抛出异常阻断业务逻辑
  • THREAD_SAFE 保证多线程访问安全,unlock会在事务完成后再提交。缺点:会使lock的作用域膨胀。直至上下文事务完成
(4)lockFailStrategy

加锁失败的处理策略:

  • NO_OPERATION:继续执行业务逻辑,不做任何处理
  • FAIL_FAST:快速失败
  • KEEP_ACQUIRE:一直阻塞,直到获得锁,在太多的尝试后,仍会报错
  • CUSTOMER: 自定义,用于全局默认处理
(5)lockExceptionStrategy

加锁异常的处理策略:

  • THROW_EXCEPTION:抛出异常
  • CUSTOMER:自定义,用于全局默认处理
(6)releaseTimeoutStrategy

释放锁时报错的处理策略:

  • NO_OPERATION:继续执行业务逻辑,不做任何处理
  • FAIL_FAST:快速失败,可自定义异常类及报错信息
  • CUSTOMER: 自定义,用于全局默认处理

三:CUSTOMER的SPI扩展示例

1.SPI扩展点

以上的策略中,lockFailStrategy,lockExceptionStrategy,releaseTimeoutStrategy 都提供了CUSTOMER的的策略,框架通过java的SPI机制,将对应的用户自实现的策略加载

策略点

策略名

具体配置名

扩展定义接口

加锁失败的处理策略 lockFailStrategy CUSTOMER cn.techwolf.blue.usl.framework.lock.handler.lock.ExceptionOnLockCustomerHandler
加锁异常的处理策略 lockExceptionStrategy CUSTOMER cn.techwolf.blue.usl.framework.lock.handler.lock.FailOnLockCustomerHandler
加锁释放锁异常的处理策略 releaseTimeoutStrategy CUSTOMER cn.techwolf.blue.usl.framework.lock.handler.release.ReleaseTimeoutCustomerHandler
2.使用示例

这里以ExceptionOnLockCustomerHandler 作为示例

(1)在resources文件夹下创建文件夹META-INF/services

(2)在META-INF/services中添加file,名称为扩展的Handler的全限定类名

(3)文件中填写自己基于定义的接口的实现类的全限定类名

自定义处理策略加载后,如果需要指定为全局,需要在全局配置中指定定位的策略名的配置为CUSTOMER即可开启,方法级(或者注解)同理

注意:无论是全局还是注解的方法级,一旦指定以上策略的配置为CUSTOMER,则系统运行时必须存在对应的实现类,否则报错。不同的是,全局级配置报错将导致项目无法启动

四:代码示例

1.代码方式

@Autowired

LockRegistry lockRegistry;

public void testApi() throws Exception {

    Lock lock = lockRegistry.obtain("aaa");

    try {

        boolean b = lock.tryLock(2, TimeUnit.SECONDS);

        if (b){

            //do your business code

        }

    }finally {

        lock.unlock();

    }

}

2:注解方式示例
(1).方法头部同时存在@Transactional及@Lock时

@Lock(waitTime = 10, keys = {"#param"}, timeUnit = TimeUnit.SECONDS, lockFailStrategy = FailOnLockStrategy.FAIL_FAST)

@Transactional

public String getValue(String param) throws Exception {

    if ("sleep".equals(param)) {//线程休眠或者断点阻塞,达到一直占用锁的测试效果

        Thread.sleep(100 10);

    }

    return "success";

}

其中:当方法存在@Transactional时,@Lock方法将在 @Transactional之后执行,即:事务开启前上锁,事务关闭后解锁。与两个注解的上下顺序无关

(2).@LockKey的使用

@Lock(keys = {"#userId"})

public String getValue(String userId, @LockKey Integer id) throws Exception {

    Thread.sleep(60 10);

    return "success";

}

按照${name}:${key1}:...:${keyN}:${@LockKey1}:...:${@LockKeyN}的拼接逻辑  以上示例的key:${userId}:${id}

(3).快捷注解的使用

@FailFastLock(keys = {"#user.id"})

public String getValueWithFailFastLock(User user) {

    try {

        Thread.sleep(1000);

    catch (InterruptedException e) {

        e.printStackTrace();

    }

    return "success";

}

@LocalLock(keys = {"#user.id"})

public String getValueWithLocalLock(User user) {

    try {

        Thread.sleep(1000);

    catch (InterruptedException e) {

        e.printStackTrace();

    }

    return "success";

}

@FailFastLock 快速失败的锁,无需设置等待时间,等待时间为0s

@LocalLock 本地jvm实现的锁

4().自定义快速失败时,抛出的异常类型及异常信息(可单独设置)

@Lock(name = "foo-service", waitTime = 1, exceptionClass = "techwolf.blue.usl.framework.springboot.lock.test.customer.exception.CustomerException",exceptionMsg = "我是注解自定义异常信息")

public void foo10() {

    try {

        log.info("acquire lock");

        TimeUnit.SECONDS.sleep(2);

    catch (InterruptedException e) {

        e.printStackTrace();

    }

}

(5).定制上锁失败策略

如果指定的customLockFailStrategy方法在本类外部,使用全限定名称

@Lock(name = "foo-service",waitTime = 2,customLockFailStrategy = "customLockTimeout")

public String foo4(String foo, String bar) {

    try {

        TimeUnit.SECONDS.sleep(2);

        log.info("acquire lock");

    catch (InterruptedException e) {

        e.printStackTrace();

    }

    return "foo4";

}

private String customLockTimeout(String foo, String bar) {

    return "custom foo:" + foo + " bar:" + bar;

}