rdf-component-lock
基于注解实现的分布式锁Java组件,废话不多说,直接上使用方式和效果。
一、引入依赖
- 引入maven依赖
可直接在maven项目pom添加如下依赖,可以直接拉取改依赖,但前提是配置了本人Gitee私服仓库!配置方式
<dependencies>
<dependency>
<groupId>com.lsl.rdf</groupId>
<artifactId>rdf-component-lock</artifactId>
<!-- 最新版本 -->
<version>1.0.0-RELEASE</version>
</dependency>
</dependencies>
- 直接jar包引入
项目jar包本人已经打包部署到个人的私服仓库中了,可自行下载需要的jar及版本!下载地址
二、使用方式
1. 配置方式
a. 基于Enable注解方式配置
直接在启动类上面添加@EnableDistributedLock
注解就ok了
@SpringBootApplication
@EnableDistributedLock
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
启动项目可以看到组件对于的Bean已经初始化完成的log日志,如果启动看不到日志,证明组件相关的Bean并没有创建成功。需要检查是否创建了相关的Bean,他们的依赖关系如下:
DistributedLock -> RedissonClient
SimpleDistributedLockAop -> DistributedLock
DistributedLockAop -> DistributedLock -> SqlSessionFactory
这里为啥是两个AOP下面会有解释。
2021-04-30 14:45:15.885 INFO 17384 --- [ main] c.l.rdf.config.DistributedLockAopConfig : DistributedLock initialization completed.
2021-04-30 14:45:15.886 INFO 17384 --- [ main] c.l.rdf.config.DistributedLockAopConfig : SimpleDistributedLockAop initialization completed.
2021-04-30 14:45:15.886 INFO 17384 --- [ main] c.l.rdf.config.DistributedLockAopConfig : DistributedLockAop initialization completed.
注:因为该组件分布式锁是基于redis
实现的,且是基于redisson
实现上锁解锁的,所以如果项目没有配置RedissonClient
需要先配置好,这是使用前提。
如果项目已经配置好了则可以忽略该配置,如果还没有配置自行配置或通过组件提供的方法配置,配置方式也很简单。如下:
- 在Spring项目配置文件application.properties添加reids配置
## redis 配置
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.database=0
- 新增配置类
ApplicationConfig
,添加如下配置,RedissonClient
即可配置完成
@Component
public class ApplicationConfig {
@Autowired
private RedisProperties redisProperties;
@Bean
public RedissonClient redissonClient() {
return new RedissonConfig(redisProperties).createSingle();
}
}
b. 自定义配置
新增配置类ApplicationConfig
,添加需要创建的Bean,如下:
@Component
public class ApplicationConfig {
@Autowired
private RedisProperties redisProperties;
@Bean
public RedissonClient redissonClient() {
return new RedissonConfig(redisProperties).createSingle();
}
@Bean
public DistributedLock distributedLock() {
return new DistributedLockImpl();
}
@Bean
public SimpleDistributedLockAop simpleDistributedLockAop() {
return new SimpleDistributedLockAop();
}
// @Bean
// public DistributedLockAop distributedLockAop() {
// return new DistributedLockAop();
// }
}
上面已经提到了,RedissonClient
是必要的Bean,DistributedLock
也是必要的,SimpleDistributedLockAop
和DistributedLockAop
则可二选一,
也可以两个都使用。SimpleDistributedLockAop
仅支持简单的上锁解锁没有多余的处理,而DistributedLockAop
则可以处理事务存在和一级缓存存在的情况,
能够保证处理存在事务和二次确认存在一级缓存的时候能够锁住。(这里这么处理是我们生产实际遇到坑后进行的改进优化,有机会再做分享)
2. 注解的使用
组件提供的注解有LockMethod
,LockSimple
,LockTarget
。
LockSimple
注解对应的是 SimpleDistributedLockAop
,LockMethod
注解对应的是 DistributedLockAop
,也就是注解要生效,要配置好对应的aop。
LockMethod
,LockSimple
用于指定上锁的方法,LockTarget
用于指定上锁方法入参,直接看例子把。
- 直接锁整个方法(不推荐),这样锁粒度太大。
@Service
public class DemoServiceImpl implements DemoService {
@Override
@LockSimple
public String simpleLockMethod() {
return "name";
}
}
redis中的key
org.example.service.impl.DemoServiceImpl_simpleLockMethod
@LockTarget
可以指定入参,并通过el表达式解析获取入参值,拼接到上锁的key中,可以减小上锁粒度。
@Service
public class DemoServiceImpl implements DemoService {
@Override
@LockSimple(el = "#name")
public String lockByCondition(@LockTarget("name") String name) {
return name;
}
}
redis中的key
org.example.service.impl.DemoServiceImpl_lockByCondition:zhangsn
- el表达式可以取对象中的某个属性,还可以进行三目运算
@Service
public class DemoServiceImpl implements DemoService {
@Override
@LockSimple(el = "#user.id + '_' + #user.name + '_' + (#user.flag ? 'true' : 'false')", waitSeconds = 5, overtimeSeconds = 60)
public String lockByObj(@LockTarget("user") User user) {
return user.getName();
}
}
redis中的key
org.example.service.impl.DemoServiceImpl_lockByObj:10000_rdf_true
- 可以指定多个入参对象
@Service
public class DemoServiceImpl implements DemoService {
@Override
@LockSimple(el = "#id + '_' + #name" )
public String lockMultiParam(@LockTarget("id") Integer id, @LockTarget("name") String name) {
return name;
}
}
redis中的key
org.example.service.impl.DemoServiceImpl_lockMultiParam:1111_zhangsn
3. 异常说明
正常异常情况下会有一下异常,使用时可针对这两种异常做相应处理(如果需要的话)。
LockWaitOverTimeException
等待锁超时异常;AcquireDistributedLockException
获取分布式锁异常;
三、其他说明
以上就是该组件的用法了,LockMethod
一样的用法,就是字段不同而已,看着很复杂,其实你懂的话用起来式很简单的,有些以看就懂的字段在这就不做过多的说明了。
如果你懂aop的话,你应该知道它是基于动态代理实现的,而动态代理的对象必须是实现接口的对象,所以普通的方法是无法加锁的,还有就是多层调用锁也是失效的,如A()方法
加了锁,调用加了锁的B()方法,这时B()方法时无法上锁的,A()方法锁有效。
组件开发环境jdk版本是1.8.0_271
,所以使用环境至少应该是jdk1.8或以上,低版本也可尝试使用,只是没有测试过,组件是经过正式环境的洗礼过的,可放心使用。
锁名称默认是包路径+类名+方法名
,这是固定的,然后可通过el表达式和入参在默认所名称上追加内容,能够减小锁粒度,提高效率。
四、联系作者
有发现有bug、建议或者有什么问题想问的,欢迎随时联系。
- QQ群:1083977145
- 邮箱:lsl.yx@foxmail.com
五、更多推荐
可视化的Mybatis反编译工具,帮助你根据数据库表生成entity,dao接口和Mapper映射文件。
提供枚举常用的几种方法,再也不用复制粘贴了,同时提供枚举描述的自动透出。