1. 程式人生 > >Springboot(十三)分散式鎖redisson

Springboot(十三)分散式鎖redisson

前言:

      分散式鎖一般有三種實現方式:

        1.基於資料庫的樂觀鎖

        2.基於redis的分散式鎖

        3.基於zookeepr的分散式鎖

    本文介紹第二種,基於redis的分散式鎖,官方推薦用redisson,redisson支援四種連線方式,文中寫了兩種一個是單體,一個是叢集

Cluster叢集,Sentinel哨兵,Master/Slave主從,Single單體

程式碼:自己搭建一個springboot工程

   程式碼中有詳細註釋,就不介紹具體方法了

首先寫一個屬性配置類,用來注入redis鎖的一些配置資訊:

package com.xhx.springboot.properties;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

/**
 * xuhaixing
 * 2018/7/2 18:16
 **/

@ConfigurationProperties(prefix ="redisson")
public class RedissonProperties {
    private String address;
    private String password;
    //毫秒
    private int timeout=30000;
    private int database=0;
    private String sentinelAddress;
    private int connectionPoolSize=150;
    private int connectionMiniumIdleSize=10;
    private int slaveConnectionPoolSize=300;
    private int masterConnectionPoolSize=300;
    private String[] sentinelAddresses;
    private String[] masterAddresses;
    //毫秒
    private int scanInterval=2000;
    private String masterName;

    public String[] getMasterAddresses() {
        return masterAddresses;
    }

    public void setMasterAddresses(String[] masterAddresses) {
        this.masterAddresses = masterAddresses;
    }

    public int getScanInterval() {
        return scanInterval;
    }

    public void setScanInterval(int scanInterval) {
        this.scanInterval = scanInterval;
    }

    public int getMasterConnectionPoolSize() {
        return masterConnectionPoolSize;
    }

    public void setMasterConnectionPoolSize(int masterConnectionPoolSize) {
        this.masterConnectionPoolSize = masterConnectionPoolSize;
    }

    public String getMasterName() {
        return masterName;
    }

    public void setMasterName(String masterName) {
        this.masterName = masterName;
    }

    public int getConnectionPoolSize() {
        return connectionPoolSize;
    }

    public void setConnectionPoolSize(int connectionPoolSize) {
        this.connectionPoolSize = connectionPoolSize;
    }

    public int getConnectionMiniumIdleSize() {
        return connectionMiniumIdleSize;
    }

    public void setConnectionMiniumIdleSize(int connectionMiniumIdleSize) {
        this.connectionMiniumIdleSize = connectionMiniumIdleSize;
    }

    public int getSlaveConnectionPoolSize() {
        return slaveConnectionPoolSize;
    }

    public void setSlaveConnectionPoolSize(int slaveConnectionPoolSize) {
        this.slaveConnectionPoolSize = slaveConnectionPoolSize;
    }

    public String[] getSentinelAddresses() {
        return sentinelAddresses;
    }

    public void setSentinelAddresses(String[] sentinelAddresses) {
        this.sentinelAddresses = sentinelAddresses;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public int getDatabase() {
        return database;
    }

    public void setDatabase(int database) {
        this.database = database;
    }

    public String getSentinelAddress() {
        return sentinelAddress;
    }

    public void setSentinelAddress(String sentinelAddress) {
        this.sentinelAddress = sentinelAddress;
    }
}

寫一個redisson.properties配置檔案

redisson.address=redis://192.168.94.151:6379
redisson.password=xuhaixing
redisson.timeout=3000
redisson.database=0

maven中引入redisson的包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.xhx.springboot</groupId>
    <artifactId>distribute-lock</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>distribute-lock</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.RELEASE</version>
        <relativePath/>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.6.5</version>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.7</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

配置類,注入RedissonClient,程式中用RedissonClient操作鎖

package com.xhx.springboot.config;

import com.xhx.springboot.properties.RedissonProperties;
import org.apache.commons.lang3.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * xuhaixing
 * 2018/7/2 18:25
 **/
@Configuration
@AutoConfigureAfter(value = {RedissonProperties.class})
public class RedissonAutoConfiguration {

    @Autowired
    private RedissonProperties redissonProperties;


    /**
     * 單體的
     * @return
     */
    @Bean
    @ConditionalOnProperty(value = "redisson.address")
    public RedissonClient redissonSingle(){
        Config config = new Config();
        SingleServerConfig serverConfig = config.useSingleServer().setAddress(redissonProperties.getAddress())
                .setTimeout(redissonProperties.getTimeout())
                .setDatabase(redissonProperties.getDatabase())
                .setConnectionPoolSize(redissonProperties.getConnectionPoolSize())
                .setConnectionMinimumIdleSize(redissonProperties.getConnectionMiniumIdleSize());
        if(StringUtils.isNotEmpty(redissonProperties.getPassword())){
            serverConfig.setPassword(redissonProperties.getPassword());
        }
        return Redisson.create(config);
    }

    /**
     * 叢集的
     * @return
     */
    @Bean
    @ConditionalOnProperty(value = "redisson.masterAddresses")
    public RedissonClient redissonSentinel(){
        Config config = new Config();
        ClusterServersConfig serverConfig = config.useClusterServers().addNodeAddress(redissonProperties.getMasterAddresses())
                .setTimeout(redissonProperties.getTimeout())
                //設定叢集掃描時間
                .setScanInterval(redissonProperties.getScanInterval())
                //主節點執行緒池數量
                .setMasterConnectionPoolSize(redissonProperties.getMasterConnectionPoolSize())
                //從節點執行緒池數量
                .setSlaveConnectionPoolSize(redissonProperties.getSlaveConnectionPoolSize());

        if(StringUtils.isNotEmpty(redissonProperties.getPassword())){
            serverConfig.setPassword(redissonProperties.getPassword());
        }
        return Redisson.create(config);
    }
}

封裝了一個分散式鎖的父類:

package com.xhx.springboot.lock;

import org.redisson.api.RLock;

import java.util.concurrent.TimeUnit;

/**
 * xuhaixing
 * 2018/7/2 17:56
 **/
public interface DistributedLocker {
    RLock lock(String lockKey);
    RLock lock(String lockKey,int timeout);
    RLock lock(String lockKey, TimeUnit unit,int timeout);
    boolean tryLock(String lockKey,TimeUnit unit,int waitTime,int leaseTime);
    void unlock(String lockKey);
    void unlock(RLock lock);
}

子類:

package com.xhx.springboot.lock;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * xuhaixing
 * 2018/7/2 18:03
 **/
@Component
public class RedissonDistributedLocker implements DistributedLocker {

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 沒有超時時間,預設30s
     * @param lockKey
     * @return
     */
    @Override
    public RLock lock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock();
        return lock;
    }

    /**
     * 自己設定超時時間
     * @param lockKey 鎖的key
     * @param timeout  秒  如果是-1,直到自己解鎖,否則不會自動解鎖
     * @return
     */
    @Override
    public RLock lock(String lockKey, int timeout) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(timeout, TimeUnit.SECONDS);
        return lock;
    }

    @Override
    public RLock lock(String lockKey, TimeUnit unit, int timeout) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(timeout,unit);
        return lock;
    }

    /**
     *
     * @param lockKey  鎖key
     * @param unit  鎖單位
     * @param waitTime   等到最大時間,強制獲取鎖
     * @param leaseTime  鎖失效時間
     * @return
     */
    @Override
    public boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime,leaseTime,unit);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public void unlock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.unlock();
    }

    @Override
    public void unlock(RLock lock) {
        lock.unlock();
    }

}

啟動類:

package com.xhx.springboot;

import com.xhx.springboot.properties.RedissonProperties;
import org.redisson.api.RedissonClient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.PropertySource;

@SpringBootApplication
@PropertySource(value = {"classpath:redisson.properties"})
@EnableConfigurationProperties(value = {RedissonProperties.class})
public class DistributeLockApplication {

    public static void main(String[] args) {
        SpringApplication.run(DistributeLockApplication.class, args);
    }
}

測試類:

package com.xhx.springboot;

import com.xhx.springboot.lock.RedissonDistributedLocker;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class DistributeLockApplicationTests {

    @Autowired
    private RedissonDistributedLocker redissonLocker;

    @Test
    public void contextLoads() throws Exception {
        int count = 10;
        CountDownLatch latch = new CountDownLatch(count);
        for (int i = 0; i < count; i++) {
            Thread thread = new Thread(() -> {
                try {
                    String lockKey = "17631701110";
                    redissonLocker.tryLock(lockKey, TimeUnit.SECONDS, 100, 8);
                    System.out.println("===加鎖===" + Thread.currentThread().getName());

                    System.out.println("===做自己操作===");
                    Thread.sleep(5000);

                    System.out.println("===釋放鎖===" + Thread.currentThread().getName());
                    redissonLocker.unlock(lockKey);

                    System.out.println(latch.getCount());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                latch.countDown();
            });
            thread.start();

        }
        latch.await();
    }

}

程式執行結果:

相關推薦

Springboot十三分散式redisson

前言:      分散式鎖一般有三種實現方式:        1.基於資料庫的樂觀鎖        2.基於redis的分散式鎖        3.基於zookeepr的分散式鎖    本文介紹第二種,基於redis的分散式鎖,官方推薦用redisson,redisson支援

SpringBoot、Redis、JedisJedisPool 分散式分散式限流 詳解

前言:網上針對基於Redis的分散式鎖,分散式限流的教程很多,也很全面,但是大多重點著墨於分散式鎖和限流的實現細節,筆者閱讀完之後,可以很好的梳理出 相應的邏輯,但是具體操作時,卻發現缺少了Jedis連線池的部分細節,導致仍然要花點時間去研究下,所以 筆者想寫一篇Blog從頭至尾介紹 Je

JMeter學習十三分散式部署

Jmeter 是java 應用,對於CPU和記憶體的消耗比較大,因此,當需要模擬數以千計的併發使用者時,使用單臺機器模擬所有的併發使用者就有些力不從心,甚至會引起JAVA記憶體溢位錯誤。為了讓jmeter工具提供更大的負載能力,jmeter短小精悍一有了使用多臺機器同時產生負載的

Curator教程分散式

共享鎖 @Testpublic void sharedLock() throws Exception {    // 建立共享鎖     InterProcessL

分散式技術分散式

1. 資料庫鎖 有兩種方式: (1)利用唯一鍵(主鍵):資料庫是有唯一主鍵規則的,主鍵不能重複,對於重複的主鍵會丟擲主鍵衝突異常。當我們想要鎖住某個方法時,執行以下SQL: insert into methodLock(me

SpringBoot十三SpringBoot整合RabbitMQ

如果對RabbitMQ不熟悉的,建議先看RabbitMQ系列教程。 一、環境準備 RabbitMQ 3.7.4 SpringBoot 1.5.10.RELEASE <dependency>

Zookeeper分散式

獲取鎖實現思路: 1.     首先建立一個作為鎖目錄(znode),通常用它來描述鎖定的實體,稱為:/lock_node 2.     希望獲得鎖的客戶端在鎖目錄下建立znode,作為鎖/lock_node的子節點,並且節點型別為有序臨時節點(EPHEMERAL_SE

企業分布式微服務雲SpringCloud SpringBoot mybatis 十三Spring Boot整合MyBatis

ech 字段 osc 操作 with public assert 連接 ref Spring中整合MyBatis就不多說了,最近大量使用Spring Boot,因此整理一下Spring Boot中整合MyBatis的步驟。搜了一下Spring Boot整合MyBatis的文

企業級 SpringBoot 教程 十三springboot集成spring cache

測試 uav exc stc 入口 時間 操作mysql 第三方 其他 本文介紹如何在springboot中使用默認的spring cache, 聲明式緩存 Spring 定義 CacheManager 和 Cache 接口用來統一不同的緩存技術。例如 JCache、 Eh

SpringBoot之HandlerInterceptor攔截器的使用 ——分散式叢集防重複提交

看本篇部落格前應當先看完前面三篇,這一篇是基於前面三篇的知識點的整合。所以很多重複的程式碼這裡就不寫出了 後臺通過攔截器和redis實現防重複提交,避免因為網路原因導致多次請求同時進入業務系統,導致資料錯亂,也可以防止對外暴露給第三方的介面在業務尚未處理完的情況下重複呼叫。

大資料十三:MapJoinDistributedCache分散式快取、資料清理例項與計數器應用

一、在map端表合併(DistributedCache分散式快取) 1.適用場景         適合用於關聯表中有小表的情形。         可以將小表分發到所有的

十三springboot實戰rabbitmq --- direct模式

上篇文章介紹了rabbitmq的原理實現,如果不知道rabbitmq的原理實現的童鞋推薦先看下上篇文章在繼續這章的實踐。 windows本地安裝rabbitmq介紹 springboot整合rabbitmq實戰 ------ direct模式 首先建立兩個spr

SpringBoot從入門到放棄》之第十三篇——使用@Async非同步呼叫,ThreadPoolTaskScheduler執行緒池,使用Future以及定義超時

建立 TaskPoolConfig 類,配置執行緒池: package com.test.util; import org.springframework.context.annotation.Bean; import org.springframework.cont

十三java springboot b2b2c多使用者商城系統分析 - SSO單點登入之OAuth2.0 根據token獲取使用者資訊(4)

上一篇我根據框架中OAuth2.0的使用總結,畫了SSO單點登入之OAuth2.0 登出流程,今天我們看一下根據使用者token獲取yoghurt資訊的流程: ​ /** * 根據token獲取使用者資訊 * @param accessToken * @return * @

Spring Cloud十三 Sleuth和Zipkin分散式鏈路跟蹤

Spring Cloud(十三) Sleuth和Zipkin分散式鏈路跟蹤 隨著業務發展,系統拆分導致系統呼叫鏈路愈發複雜一個前端請求可能最終需要呼叫很多次後端服務才能完成,當整個請求變慢或不可用時,我們是無法得知該請求是由某個或某些後端服務引起的,這時就需要解決如何快讀定位服務故障

Java springcloud B2B2C o2o多使用者商城 springcloud架構十三springboot整合spring cache

本文介紹如何在springboot中使用預設的spring cache, 宣告式快取 Spring 定義 CacheManager 和 Cache 介面用來統一不同的快取技術。例如 JCache、 EhCache、 Hazelcast、 Guava、 Redis 等。在使用 Spring 整

zookeeper快速入門——應用兩種分散式

        在《zookeeper快速入門——簡介》一文中,我們介紹了zookeeper的機制。但是還是比較抽象,沒有直觀感受到它在分散式系統中的應用。本文我們使用一個例子,三次迭代演進,來說明Zookeeper Client端和Server端如何配合以實現分散式協作。(

SpringBoot學習-十三SpringBoot中建立WebSocket連線(STOMP)

STOMP協議介紹 STOMP,Streaming Text Orientated Message Protocol,是流文字定向訊息協議,是一種為MOM(Message Oriented Middleware,面向訊息的中介軟體)設計的簡單文字協議。 它提

分散式-zookeeper-SharedLock基於InterProcessSemaphoreMutex分散式共享

分散式共享鎖:InterProcessSemaphoreMutex完全分佈的全域性同步鎖,意味著在任何快照時間,沒有兩個客戶端認為他們擁有相同的鎖,繼承上一篇分散式鎖-zookeeper的Abstrac

企業分散式微服務雲SpringCloud SpringBoot mybatis 十三斷路器聚合監控(Hystrix Turbine)

講述瞭如何利用Hystrix Dashboard去監控斷路器的Hystrix co