Giter Site home page Giter Site logo

kekingcn / spring-boot-klock-starter Goto Github PK

View Code? Open in Web Editor NEW
812.0 44.0 285.0 309 KB

基于redis的分布式锁组件,简单方便快捷接入项目,使项目拥有分布式锁能力

Home Page: https://gitee.com/kekingcn/spring-boot-klock-starter

License: Apache License 2.0

Java 100.00%
redis redisson lock spring-boot spring springboot klock

spring-boot-klock-starter's Introduction

spring-boot-klock-starter

基于redis的分布式锁spring-boot starter组件,使得项目拥有分布式锁能力变得异常简单,支持spring boot,和spirng mvc等spring相关项目

快速开始

spring boot项目接入

1.添加klock starter组件依赖

<dependency>
    <groupId>cn.keking</groupId>
    <artifactId>spring-boot-klock-starter</artifactId>
    <version>1.5-RELEASE</version>
</dependency>

2.application.properties配置redis链接:spring.klock.address=redis://127.0.0.1:6379

3.在需要加分布式锁的方法上,添加注解@Klock,如:

@Service
public class TestService {

    @Klock(waitTime = Long.MAX_VALUE)
    public String getValue(String param) throws Exception {
        if ("sleep".equals(param)) {//线程休眠或者断点阻塞,达到一直占用锁的测试效果
            Thread.sleep(1000 * 50);
        }
        return "success";
    }
}

4.支持锁指定的业务key,如同一个方法ID入参相同的加锁,其他的放行。业务key的获取支持Spel,具体使用方式如下
使用示例

spring mvc项目接入

其他步骤和spring boot步骤一样,只需要spring-xx.xml配置中添加KlockAutoConfiguration类扫描即可,如:

<context:component-scan base-package="org.springframework.boot.autoconfigure.klock.KlockAutoConfiguration"/>

使用参数说明

配置参数说明

spring.klock.address  : redis链接地址 如 redis://127.0.0.1:6379
spring.klock.password : redis密码
spring.klock.database : redis数据索引
spring.klock.waitTime : 获取锁最长阻塞时间(默认:60,单位:秒)
spring.klock.leaseTime: 已获取锁后自动释放时间(默认:60,单位:秒)
spring.klock.cluster-server.node-addresses : redis集群配置 如 redis://127.0.0.1:7000,redis://127.0.0.1:7001,redis://127.0.0.1:7002
#spring.klock.address 和 spring.klock.cluster-server.node-addresses 选其一即可

@Klock注解参数说明

@Klock可以标注四个参数,作用分别如下
name:lock的name,对应redis的key值。默认为:类名+方法名
lockType:锁的类型,目前支持(可重入锁,公平锁,读写锁)。默认为:公平锁
waitTime:获取锁最长等待时间。默认为:60s。同时也可通过spring.klock.waitTime统一配置
leaseTime:获得锁后,自动释放锁的时间。默认为:60s。同时也可通过spring.klock.leaseTime统一配置
lockTimeoutStrategy: 加锁超时的处理策略,可配置为不做处理、快速失败、阻塞等待的处理策略,默认策略为不做处理

customLockTimeoutStrategy: 自定义加锁超时的处理策略,需指定自定义处理的方法的方法名,并保持入参一致
releaseTimeoutStrategy: 释放锁时,持有的锁已超时的处理策略,可配置为不做处理、快速失败的处理策略,默认策略为不做处理
customReleaseTimeoutStrategy: 自定义释放锁时,需指定自定义处理的方法的方法名,并保持入参一致

锁超时说明

因为基于redis实现分布式锁,如果使用不当,会在以下场景下遇到锁超时的问题:
锁超时处理逻辑

加锁超时处理策略(LockTimeoutStrategy):

  • NO_OPERATION 不做处理,继续执行业务逻辑
  • FAIL_FAST 快速失败,会抛出KlockTimeoutException
  • KEEP_ACQUIRE 阻塞等待,一直阻塞,直到获得锁,但在太多的尝试后,会停止获取锁并报错,此时很有可能是发生了死锁。
  • 自定义(customLockTimeoutStrategy) 需指定自定义处理的方法的方法名,并保持入参一致,指定自定义处理方法后,会覆盖上述三种策略,且会拦截业务逻辑的运行。

释放锁时超时处理策略(ReleaseTimeoutStrategy):

  • NO_OPERATION 不做处理,继续执行业务逻辑
  • FAIL_FAST 快速失败,会抛出KlockTimeoutException
  • 自定义(customReleaseTimeoutStrategy) 需指定自定义处理的方法的方法名,并保持入参一致,指定自定义处理方法后,会覆盖上述两种策略, 执行自定义处理方法时,业务逻辑已经执行完毕,会在方法返回前和throw异常前执行。

希望使用者清楚的意识到,如果没有对加锁超时进行有效设置,那么设置释放锁时超时处理策略是没有意义的。

在测试模块中已集成锁超时策略的使用用例

关于测试

工程test模块下,为分布式锁的测试模块。可以快速体验分布式锁的效果。

使用登记

如果这个项目解决了你的实际问题,可在 https://gitee.com/kekingcn/spring-boot-klock-starter/issues/IH4NE 登记下,如果节省了你的研发时间,也愿意支持下的话,可点击下方【捐助】请作者喝杯咖啡,也是非常感谢

spring-boot-klock-starter's People

Contributors

gitchenjh avatar klboke avatar wanglaomo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spring-boot-klock-starter's Issues

指定lock的name属性,redis设置的key并不止name,还是会加上其他的字符

@klock可以标注四个参数,作用分别如下

name:lock的name,对应redis的key值。默认为:类名+方法名
我根据这个属性,想实现这个方法加锁(有参数), 不管参数值是什么,但得不到我想要的结果.
最后发现LockInfoProvider这个类中获取lock的name,会加上businessKeyName,
是我理解错了这个参数的意思? 按照文档的描述,加上@KlockKey才应该是这样的结果,
或者有其他方式可以实现我的需求?

如果不配置klock的 redis配置,是否使用默认的redis

我测试 没有配置
spring.klock.address : redis链接地址
spring.klock.password : redis密码
spring.klock.database : redis数据索引

也可以使用,是否使用了默认的redis配置
redis:
host: xxx
port: xxx
password: xxxxx
database: 3

这样是不是可以不再配置 klock 也是可以使用的

同一线程中嵌套调用引发的问题

在同一线程中,如果由一个带klock锁(锁A)的方法调用另一个带klock锁(锁B)的方法,currentThreadLock中的锁信息将会更新(锁A->锁B),
currentThreadLock.set(lock); currentThreadLockRes.get().setRes(true);

并且在两个方法退出时,都会触发KlockAspectHandler类中releaseLock方法的调用,
LockRes lockRes = currentThreadLockRes.get(); if (lockRes.getRes()) { boolean releaseRes = currentThreadLock.get().release(); // avoid release lock twice when exception happens below lockRes.setRes(false); if (!releaseRes) { handleReleaseTimeout(klock, lockRes.getLockInfo(), joinPoint); } }
由于第一次触发时,currentThreadLock和currentThreadLockRes中的锁信息会被清空,所以第二次触发将会报NPE。请教下,这种单一线程只支持加一次锁的设计,是有什么原因吗?另在有currentThreadLock这个ThreadLocal保证单一线程只有一个锁有效的前提下,currentThreadLockRes存在的意义是什么?

klock不生效

您好,在springboot项目中,运用了klock,用法如下:
@klock
@scheduled(fixedRate = 500)
public get(){
}
klock配置如下:
waitTime: 600
leaseTime: 600
但发现偶尔还是会导致get方法执行两次,请问下我的用法是否有问题?

redis配置问题

默认读取系统的redis然后注入,不需要那么复杂,或者找不到时默认注入session对象也行

自定义处理方法

image
image
自定义超时以及释放锁的处理方法,入参是方法名,但是会报错没有这个方法,这里入参是全限定路径还是什么?

#KlockAspectHandler 类的疑问

        try {
            currentThreadLock = lock.acquire();
            return joinPoint.proceed();
        } finally {
            if (currentThreadLock) {
                lock.release();
            }
        }

这是是不是应该改成

		try {
			currentThreadLock = lock.acquire();
			if (currentThreadLock) {
				joinPoint.proceed();
			}
			return null;
		} finally {
			if (currentThreadLock) {
				lock.release();
			}
		}

拿到锁再执行业务逻辑

很优秀的开源分布式锁,请问还维护吗

hello 作者,
我们项目需要用到分布式锁,觉得你这个项目非常棒,但很多依赖库都非常旧了,我们是基于Spring-boot 2.1.8 开发的应用,各种不兼容,需要拉去代码升级里面的spring库重新编译才可以使用。请问现在还维护吗,我给你提一个PR然后重新发布一个高版本的包

@KlockKey 方法参数为null时报空指针

@KlockKey 业务key 参数为null是会报空指针
KlockKey keyAnnotation = parameters[i].getAnnotation(KlockKey.class);
if (keyAnnotation.value().isEmpty()) {
parameterKey.add(parameterValues[i].toString());
}

关于 Aop 事务问题

这个项目不错👍

给几点使用的建议:

  1. Spring 中 Aop 有两种实现方式,是不是得考虑扩展?
  2. 另外目前的切面中 默认是 aop 事务先行,而后再进入切面,很多有事物的方法就不适合了
  3. 是否可以考虑多种锁的实现方式, 像 shedlock 这样

报错:求助

org.springframework.boot.autoconfigure.klock.core.KlockAspectHandler - Timeout while acquiring Lock(lock.com.example.game.controller.OrderController.xxxx)

关于keys,有几个问题想请教下

keys里面目前支持添加常量么?还有从实体类里取值做key的时候,当某个取值是null的时候,会报空指针,这个能否优化下?多谢

难道整个系统只有4把锁????

@PostConstruct
public void init(){
lockMap.put(LockType.Reentrant,new ReentrantLock(redissonClient));
lockMap.put(LockType.Fair,new FairLock(redissonClient));
lockMap.put(LockType.Read,new ReadLock(redissonClient));
lockMap.put(LockType.Write,new WriteLock(redissonClient));
logger.info("Klock Initialization Successful");
}

public Lock getLock(ProceedingJoinPoint joinPoint, Klock klock){
    LockInfo lockInfo = lockInfoProvider.get(joinPoint,klock);
    return lockMap.get(lockInfo.getType()).setLockInfo(lockInfo);
}

根据LockFactory这个类,每种类型永远只有一把锁??? 也就是同一个系统类,如果两个接口没什么关系,但是如果都用了公平锁,就意味着两个接口存在锁竞争?

maven 的依赖

只有

cn.keking
spring-boot-klock-starter
1.1-RELEASE

还请补全快速开始之类的文档,感谢分享

2022年了请问还维护吗

非常棒的工具,但是现在已经2022年,springboot都已经到2.7了,有考虑适配升级一下?

报错了。。

Can't init enough connections amount! Only 0 from 1 were initialized. 这是咋回事啊 大佬

读写锁没有意义

我有两个方法
一个写操作, 一个读操作
想在这两个方法上面使用@klock注解
实际没用, 因为两个方法上面的锁key都不一样

rLock的问题

rLock为static,当多把锁同时上锁的时候,rLock难道不会发生改变吗?

一个集群一个服务部署了多个副本,通过定时任务内部调接口提示一直被锁,返回失败。

一个集群一个服务部署了多个副本,通过xxl-job内部调接口提示一直被锁,返回失败。但如果我用swagger单独调该接口是没有问题的,我看了一下redis里面的数据,也没有上锁的key。如果是服务没有多副本的情况也是不会报错的,请问这是什么情况呢。具体的报错如下:
org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 : [{"timestamp":"2024-03-05T06:41:16.013+00:00","status":500,"path":"/v1/things/job-handler/cal-things-usage","code":"http.500","error":"Internal Server Error","message":"Failed to acquire Lock(lock.com.things.api.JobHandlerController.calThingsUsage) with timeout(1s)"}]

同一线程同一把锁重入时的问题

String curentLock = this.getCurrentLockId(joinPoint,klock); currentThreadLock.put(curentLock,new LockRes(lockInfo, false));
加锁时,这里的key是线程id+锁名。当同一线程重入这把锁时,内层释放时:
// avoid memory leak private void cleanUpThreadLocal(String curentLock) { currentThreadLock.remove(curentLock); }
会把这把锁从map里remove掉,在外层再释放时,就拿不到锁信息了:
private void releaseLock(Klock klock, JoinPoint joinPoint,String curentLock) throws Throwable { LockRes lockRes = currentThreadLock.get(curentLock); if (lockRes.getRes()) { boolean releaseRes = currentThreadLock.get(curentLock).getLock().release(); // avoid release lock twice when exception happens below lockRes.setRes(false); if (!releaseRes) { handleReleaseTimeout(klock, lockRes.getLockInfo(), joinPoint); } } }
是否应该加上计数器支持重入性?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.