跳至主要内容

在Spring Boot中使用分布式锁

Welcome file

简介

在使用分布式锁时,经常会看到各种复制粘贴的实现,也会有很多需要注意的地方,一不小心就会出一些难以察觉的问题。还好Spring对分布式锁提供了几种方便的实现,本文简单介绍一下Redis锁的实现如何使用。

使用Redis实现分布式锁

POM文件

pom文件需要引入如下包:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-integration</artifactId>
        </dependency>

        <!-- Redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.integration</groupId>
            <artifactId>spring-integration-redis</artifactId>
        </dependency>
  • 引入spring-boot-starter-web包是为了方便用web来测试

  • spring-boot-starter-integration包是包含锁的抽象

  • 最后两个redis的包是相关依赖

配置SpringBoot

新建一个Redisconfig类:

@Configuration
public class RedisConfig {

    @Bean(destroyMethod = "destroy")
    public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) {
        // 需要注意,REDIS_LOCK是可配置的该锁的命名空间,需要所有地方都统一用同一个
        // 最后一个参数配置锁的默认过期时间,单位是MS
        return new RedisLockRegistry(redisConnectionFactory, "REDIS_LOCK",10000);
    }

}

在application.properties中配置对应的连接参数:

spring.redis.database=0
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.timeout=60000

这样就做好了相关配置,下面开始测试。

新建测试类

新建一个controller测试类:

@Slf4j
@RestController
public class TestLockController {

    @Autowired
    RedisLockRegistry redisLockRegistry;

    @GetMapping("redisLock")
    public String testLock() throws InterruptedException {
        String uuid = UUID.randomUUID().toString();
        // 获取对应的锁,锁的KEY是redisTestLock,存在redis中会是 
        // REDIS_LOCK:redisTestLock
        // 前缀REDIS_LOCK就是在前面配置类中配置的
        Lock redisTestLock = redisLockRegistry.obtain("redisTestLock");

        // 尝试锁定对应的KEY,最多等待5秒
        boolean locked = redisTestLock.tryLock(5, TimeUnit.SECONDS);
        if (locked) {
            try {
                log.info("get lock success...id={}", uuid);
                Thread.sleep(20000);
                log.info("execute success..id={}", uuid);
            } finally {
                redisTestLock.unlock();
            }
        }else{
            log.info("get lock failed...id={}", uuid);
        }
        return uuid;
    }

}

测试

可以连续发起两次请求,查看结果:

curl 127.0.0.1:8080/redisLock

java控制台会输出:

get lock success...id=b529d805-e47f-462f-9252-88a446d8076f
get lock failed...id=1ff3b8e7-3215-4f73-a4a3-16ba81322499
execute success..id=b529d805-e47f-462f-9252-88a446d8076f

总结

可以看到spring提供了非常简单易用的分布式锁的实现,并且相对可靠。

参考资料

[1]Spring Integration

[2]示例工程:https://github.com/nereusyi/spring-boot-demos/tree/main/distributed-lock-demo

评论

此博客中的热门博文

国密SM2签名封装成PKCS7格式

在国内做金融行业,难免会有被强制使用国密算法的情况,而且一般还会指定必须使用硬件加密机之类的设备,所以我也稍微的研究了一下国密算法,使用软算法签名并封装 PKCS7 格式(文档中的一个交互)。 以下是基于 Bouncy Castle 的示例,密钥对的生成可以参考 Bouncy Castle 中 test 包下 SM2 相关代码 public static String sign ( ) throws Exception { //加载公钥 byte [ ] plainText = "hello, world" . getBytes ( ) ; FileInputStream input = new FileInputStream ( "F:\\certificate\\public.cer" ) ; CertificateFactory certificateFactory = new CertificateFactory ( ) ; X509Certificate certificate = ( X509Certificate ) certificateFactory . engineGenerateCertificate ( input ) ; input . close ( ) ; //加载私钥,private为换成实际的私钥 PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec ( "private" . getBytes ( ) ) ; //SM2算法实际上为ECC算法,并指定了一些参数值,所以这里的参数是EC KeyFactory factory = KeyFactory . getInstance ( "EC" , "BC" ) ; PrivateKey privateKey = factory . generatePrivate ( spec ) ; //以下为签名并封装成PKCS7格式 byte [ ] signedMessag

Spring Boot Actuator 2 示例

Welcome file 简介 Spring Boot Actuator为应用程序提供了各种开箱即用的运维特性,可以与应用方便的交互和监控。 使用环境:Java 11 和 Spring Boot 2.4.3.RELEASE 集成Spring Boot Actuator 在Spring Boot中集成Spring Boot Actuator与集成其他的框架类似,在 pom.xml 里引入相关的starter就可以: < dependency > < groupId > org.springframework.boot </ groupId > < artifactId > spring-boot-starter-actuator </ artifactId > </ dependency > < dependency > < groupId > org.springframework.boot </ groupId > < artifactId > spring-boot-starter-web </ artifactId > </ dependency > 由于大部分的使用场景还是web,所以这里也用Spring MVC做示例。 配置好 pom.xml 后,默认actuator仅暴露一些基本功能,实际使用中,根据需求暴露对应功能。为了简便测试,这里在 application.yml 中配置暴露全部功能: management : endpoints : web : exposure : include : "*" endpoint : health : enabled : true show-details : always probes : enabled : true shutdown : enabled : true metr

NextCloud数据目录迁移

最近服务器的环境坏了,所以迁移了NextCloud的数据目录。不过在迁移过程中有点小问题。 环境: Ubuntu 18.04 Docker 19.03.7 1.NextCloud页面不正常,Docker日志显示XX目录permission denied 参考了 这里 的做法,不过是把  /var/www/html/   整个目录的权限都修改为  chown -R www-data:www-data ,之后就不再报权限问题了。 2.数据库配置修改 因为NextCloud是在初始化时填的数据库连接信息,所以直接迁移数据目录的情况下,会导致应用连不到新的数据库环境。此时可以找到数据目录下的  config/config.php 文件,直接修改数据库连接配置。