目录
一:框架集成
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; } |