2 Star 5 Fork 1

瞌睡虫 / rdf-components

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
README.md 8.20 KB
一键复制 编辑 原始数据 按行查看 历史
瞌睡虫 提交于 2021-07-12 11:10 . feat[*]: 版本升级1.0.1 >> 1.0.2

rdf-component-lock

基于注解实现的分布式锁Java组件,废话不多说,直接上使用方式和效果。

一、引入依赖

  • 引入maven依赖

可直接在maven项目pom添加如下依赖,可以直接拉取改依赖,但前提是配置了本人Gitee私服仓库!配置方式

<dependencies>
    <dependency>
        <groupId>com.lsl.rdf</groupId>
        <artifactId>rdf-component-lock</artifactId>
        <!-- 最新版本 -->
        <version>1.0.2-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也是必要的,SimpleDistributedLockAopDistributedLockAop则可二选一, 也可以两个都使用。SimpleDistributedLockAop仅支持简单的上锁解锁没有多余的处理,而DistributedLockAop则可以处理事务存在和一级缓存存在的情况, 能够保证处理存在事务和二次确认存在一级缓存的时候能够锁住。(这里这么处理是我们生产实际遇到坑后进行的改进优化,有机会再做分享)

2. 注解的使用

组件提供的注解有LockMethodLockSimpleLockTargetLockSimple 注解对应的是 SimpleDistributedLockAopLockMethod 注解对应的是 DistributedLockAop,也就是注解要生效,要配置好对应的aop。 LockMethodLockSimple用于指定上锁的方法,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表达式和入参在默认所名称上追加内容,能够减小锁粒度,提高效率。

3.1 加解锁时序

分布式锁时序

四、联系作者

有发现有bug、建议或者有什么问题想问的,欢迎随时联系。

五、更多推荐

可视化的Mybatis反编译工具,帮助你根据数据库表生成entity,dao接口和Mapper映射文件。

提供枚举常用的几种方法,再也不用复制粘贴了,同时提供枚举描述的自动透出。

六、最重要的

你可以借鉴使用到你的个人项目、商业项目、毕业设计等,但不能二次开源!

还有快点个 Star!Star!Star!

Java
1
https://gitee.com/lsl-gitee/rdf-components.git
git@gitee.com:lsl-gitee/rdf-components.git
lsl-gitee
rdf-components
rdf-components
master

搜索帮助