一、简介

Lock4j是一个分布式锁组件,它供给了多种不同的支撑以满足不同性能和环境的需求,基于Spring AOP的声明式和编程式分布式锁,支撑RedisTemplate、Redisson、Zookeeper

二、特性

  • 简略易用,功能强大,扩展性强。
  • 支撑redission, redisTemplate, zookeeper,可混用,支撑扩展。

Gitee:gitee.com/baomidou/lo…

三、运用前准备

3.1 引进依赖

<!-- Lock4j -->
<!-- 若运用redisTemplate作为分布式锁底层,则需求引进 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>lock4j-redis-template-spring-boot-starter</artifactId>
    <version>2.2.4</version>
</dependency>
<!-- 若运用redisson作为分布式锁底层,则需求引进 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>lock4j-redisson-spring-boot-starter</artifactId>
    <version>2.2.4</version>
</dependency>

3.2 增加redis装备

spring:
  redis:
    database: 0
    # Redis服务器地址 写你的ip
    host: 127.0.0.1
    # Redis服务器衔接端口
    port: 6379
    # Redis服务器衔接密码(默许为空)
    password:
    # 衔接池最大衔接数(运用负值表明没有限制  类似于mysql的衔接池
    jedis:
      pool:
        max-active: 200
        # 衔接池最大阻塞等待时刻(运用负值表明没有限制) 表明衔接池的链接拿完了 现在去申请需求等待的时刻
        max-wait: -1
        # 衔接池中的最大闲暇衔接
        max-idle: 10
        # 衔接池中的最小闲暇衔接
        min-idle: 0
    # 衔接超时时刻(毫秒) 去链接redis服务端
    timeout: 6000

四、注解特点介绍

package com.baomidou.lock.annotation;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Lock4j {
    String name() default "";
    Class<? extends LockExecutor> executor() default LockExecutor.class;
    String[] keys() default {""};
    long expire() default -1L;
    long acquireTimeout() default -1L;
    boolean autoRelease() default true;
}
@Lock4j注解特点 说明
name 需求锁住的key称号
executor 可以通过该参数设置自定义特定的履行器
keys 需求锁住的keys称号,可以是多个
expire 锁过期时刻,主要是用来防止死锁
acquireTimeout 可以理解为排队等待时长,超过这个时长就退出排队,并排除获取锁超时反常
autoRelease 是否自动开释锁,默许是true

五、简略运用

@RestController
@RequestMapping("/mock")
public class MockController {
    @GetMapping("/lockMethod")
    @Lock4j(keys = {"#key"}, acquireTimeout = 1000, expire = 10000)
    public Result lockMethod(@RequestParam String key) {
        ThreadUtil.sleep(5000);
        return Result.OK(key);
    }
}

翻开浏览器窗口,重复改写拜访:http://localhost:8080/mock/lockMethod?key=123

成功获得锁拜访成果:

{
    "success": true,
    "message": "操作成功!",
    "code": 200,
    "result": "123",
    "timestamp": 1678866083211
}

抢占不到锁,Lock4j会抛出com.baomidou.lock.exception.LockFailureException: request failed,please retry it.反常,通过大局反常处理返回如下成果:

{
    "success": false,
    "message": "操作失利,request failed,please retry it.",
    "code": 500,
    "result": null,
    "timestamp": 1678866034929
}

六、高档运用

6.1 自定义履行器Exector

/**
 * 自定义分布式锁履行器
 *
 * @author: austin
 * @since: 2023/3/15 15:45
 */
@Component
public class CustomRedissonLockExecutor extends AbstractLockExecutor {
    @Override
    public Object acquire(String lockKey, String lockValue, long expire, long acquireTimeout) {
        return null;
    }
    @Override
    public boolean releaseLock(String key, String value, Object lockInstance) {
        return false;
    }
}

在注解上直接指定特定的履行器:@Lock4j(executor = CustomRedissonLockExecutor.class)

6.2 自定义分布式锁key生成器

/**
 * 自定义分布式锁key生成器
 *
 * @author: austin
 * @since: 2023/3/15 15:46
 */
@Component
public class CustomKeyBuilder extends DefaultLockKeyBuilder {
    public CustomKeyBuilder(BeanFactory beanFactory) {
        super(beanFactory);
    }
}

6.3 自定义抢占锁失利履行策略

/**
 * 自定义抢占锁失利履行策略
 *
 * @author: austin
 * @since: 2023/3/15 15:49
 */
@Component
public class GrabLockFailureStrategy implements LockFailureStrategy {
    @Override
    public void onLockFailure(String key, Method method, Object[] arguments) {
    }
}

默许的锁获取失利策略为 com.baomidou.lock.DefaultLockFailureStrategy.

6.4 手动加锁开释锁

@Service
public class LockServiceImpl implements LockService {
    @Autowired
    private LockTemplate lockTemplate;
    @Override
    public void lock(String resourceKey) {
        LockInfo lock = lockTemplate.lock(resourceKey, 10000L, 2000L, CustomRedissonLockExecutor.class);
        if (lock == null) {
            // 获取不到锁
            throw new FrameworkException("事务处理中,请稍后再试...");
        }
        // 获取锁成功,处理事务
        try {
            doBusiness();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lockTemplate.releaseLock(lock);
        }
    }
    private void doBusiness() {
        // TODO 事务履行逻辑
    }
}