在非分布式系统中要实现锁的机制很简单,利用java.util.concurrent.locks包下的Lock和关键字synchronized都可以实现。但是在分布式系统中,如何实现各个单独的微服务需要共享某个资源的时候进行有效的锁的保护机制呢?这边使用Redisson来实现。

一、Redisson简介
  Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务。Redisson提供了使用Redis的最简单和最便捷的方法。Redisson的宗旨是促进使用者对Redis的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上。更多,https://github.com/redisson/redisson/wiki/1.-%E6%A6%82%E8%BF%B0

二、springboot+redission 演示
  1、pom.xml

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>1.5.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.5.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>1.5.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.3.2</version>
</dependency>
</dependencies>

  2、application.properties

server.port=8070

# redisson
redisson.address=192.168.3.3:6379
redisson.password=test123

  3、DistributedLocker

import java.util.concurrent.TimeUnit;

/**
* 定义Lock的接口类
* @author ko
*
*/
public interface DistributedLocker { void lock(String lockKey); void unlock(String lockKey); void lock(String lockKey, int timeout); void lock(String lockKey, TimeUnit unit ,int timeout);
}

  4、RedissonDistributedLocker

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient; import com.redlock.locker.DistributedLocker; import java.util.concurrent.TimeUnit; /**
* Lock接口实现类
* @author ko
*
*/
public class RedissonDistributedLocker implements DistributedLocker { private RedissonClient redissonClient; @Override
public void lock(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock();
} @Override
public void unlock(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
lock.unlock();
} @Override
public void lock(String lockKey, int leaseTime) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock(leaseTime, TimeUnit.SECONDS);
} @Override
public void lock(String lockKey, TimeUnit unit ,int timeout) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock(timeout, unit);
} public void setRedissonClient(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
}

  5、RedissonProperties

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
* redisson属性装配类
* @author ko
*
*/
@ConfigurationProperties(prefix = "redisson")
public class RedissonProperties { private int timeout = 3000; private String address; private String password; private int connectionPoolSize = 64; private int connectionMinimumIdleSize=10; private int slaveConnectionPoolSize = 250; private int masterConnectionPoolSize = 250; private String[] sentinelAddresses; private String masterName; public int getTimeout() {
return timeout;
} public void setTimeout(int timeout) {
this.timeout = timeout;
} public int getSlaveConnectionPoolSize() {
return slaveConnectionPoolSize;
} public void setSlaveConnectionPoolSize(int slaveConnectionPoolSize) {
this.slaveConnectionPoolSize = slaveConnectionPoolSize;
} public int getMasterConnectionPoolSize() {
return masterConnectionPoolSize;
} public void setMasterConnectionPoolSize(int masterConnectionPoolSize) {
this.masterConnectionPoolSize = masterConnectionPoolSize;
} public String[] getSentinelAddresses() {
return sentinelAddresses;
} public void setSentinelAddresses(String sentinelAddresses) {
this.sentinelAddresses = sentinelAddresses.split(",");
} public String getMasterName() {
return masterName;
} public void setMasterName(String masterName) {
this.masterName = masterName;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} public String getAddress() {
return address;
} public void setAddress(String address) {
this.address = address;
} public int getConnectionPoolSize() {
return connectionPoolSize;
} public void setConnectionPoolSize(int connectionPoolSize) {
this.connectionPoolSize = connectionPoolSize;
} public int getConnectionMinimumIdleSize() {
return connectionMinimumIdleSize;
} public void setConnectionMinimumIdleSize(int connectionMinimumIdleSize) {
this.connectionMinimumIdleSize = connectionMinimumIdleSize;
}
}

  6、RedissLockUtil

import java.util.concurrent.TimeUnit;

import com.redlock.locker.DistributedLocker;

/**
* redis分布式锁工具类
* @author ko
*
*/
public class RedissLockUtil {
private static DistributedLocker redissLock; public static void setLocker(DistributedLocker locker) {
redissLock = locker;
} public static void lock(String lockKey) {
redissLock.lock(lockKey);
} public static void unlock(String lockKey) {
redissLock.unlock(lockKey);
} /**
* 带超时的锁
* @param lockKey
* @param timeout 超时时间 单位:秒
*/
public static void lock(String lockKey, int timeout) {
redissLock.lock(lockKey, timeout);
} /**
* 带超时的锁
* @param lockKey
* @param unit 时间单位
* @param timeout 超时时间
*/
public static void lock(String lockKey, TimeUnit unit ,int timeout) {
redissLock.lock(lockKey, unit, timeout);
}
}

  7、RedissonAutoConfiguration

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SentinelServersConfig;
import org.redisson.config.SingleServerConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import com.redlock.bean.RedissonProperties;
import com.redlock.locker.DistributedLocker;
import com.redlock.locker.impl.RedissonDistributedLocker;
import com.redlock.util.RedissLockUtil; /**
* Redisson+springboot 自动配置类
* @author ko
*
*/
@Configuration
@ConditionalOnClass(Config.class)
@EnableConfigurationProperties(RedissonProperties.class)
public class RedissonAutoConfiguration { @Autowired
private RedissonProperties redssionProperties; /**
* 哨兵模式自动装配
* @return
*/
@Bean
@ConditionalOnProperty(name="redisson.master-name")
RedissonClient redissonSentinel() {
Config config = new Config();
SentinelServersConfig serverConfig = config.useSentinelServers().addSentinelAddress(redssionProperties.getSentinelAddresses())
.setMasterName(redssionProperties.getMasterName())
.setTimeout(redssionProperties.getTimeout())
.setMasterConnectionPoolSize(redssionProperties.getMasterConnectionPoolSize())
.setSlaveConnectionPoolSize(redssionProperties.getSlaveConnectionPoolSize()); if(redssionProperties.getPassword() != null && !"".equals(redssionProperties.getPassword())) {
serverConfig.setPassword(redssionProperties.getPassword());
}
return Redisson.create(config);
} /**
* 单机模式自动装配
* @return
*/
@Bean
@ConditionalOnProperty(name="redisson.address")
RedissonClient redissonSingle() {
Config config = new Config();
SingleServerConfig serverConfig = config.useSingleServer()
.setAddress(redssionProperties.getAddress())
.setTimeout(redssionProperties.getTimeout())
.setConnectionPoolSize(redssionProperties.getConnectionPoolSize())
.setConnectionMinimumIdleSize(redssionProperties.getConnectionMinimumIdleSize()); if(redssionProperties.getPassword() != null && !"".equals(redssionProperties.getPassword())) {
serverConfig.setPassword(redssionProperties.getPassword());
} return Redisson.create(config); } /**
* 装配locker类,并将实例注入到RedissLockUtil中
* @return
*/
@Bean
DistributedLocker distributedLocker(RedissonClient redissonClient) {
RedissonDistributedLocker locker = new RedissonDistributedLocker();
locker.setRedissonClient(redissonClient);
RedissLockUtil.setLocker(locker);
return locker;
} }

  8、暴露接口 TestController

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; import com.redlock.util.RedissLockUtil; /**
* 测试类
* @author ko
*
*/
@RestController
public class TestController { // private static final Logger LOG = Logger.getLogger(BootApplication.class.getName());
// LOG.log(Level.INFO, "All procn"); private final String _lock = "_lock"; static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static String getCurrentDate(){
return sdf.format(new Date());
} @RequestMapping(value = "/testlock",method=RequestMethod.GET)
public String testlock(String name) { new Thread(new Runnable() { @Override
public void run() { RedissLockUtil.lock(_lock, TimeUnit.MINUTES, 10); System.out.println(getCurrentDate()+" "+name+" begin...");
for (int i = 0; i < 20; i++) {
try {
Thread.sleep(1000);
System.out.println(getCurrentDate()+" "+name+" "+i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(getCurrentDate()+" "+name+" end..."); RedissLockUtil.unlock(_lock);
}
}).start(); return "testlock";
} }

  9、微服务启动类 BootApplication

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

三、启动演示

  复制项目,第二个服务的端口改为8071,启动两个服务,先在浏览器里输入http://localhost:8070/testlock?name=zhang,3s后再输入http://localhost:8071/testlock?name=wang,3s后再输入http://localhost:8070/testlock?name=zhang1,3s后再输入http://localhost:8071/testlock?name=wang1,如果没有锁机制,打印的数据应该是交叉的,反之,同一时刻只会打印一次的请求,不会出现交叉打印数据的情况。

官方文档:https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95

Spring Cloud分布式微服务系统中利用redssion实现分布式锁的更多相关文章

  1. Spring Boot + Spring Cloud 构建微服务系统(八):分布式链路追踪(Sleuth、Zipkin)

    技术背景 在微服务架构中,随着业务发展,系统拆分导致系统调用链路愈发复杂,一个看似简单的前端请求可能最终需要调用很多次后端服务才能完成,那么当整个请求出现问题时,我们很难得知到底是哪个服务出了问题导致 ...

  2. Spring Cloud分布式微服务云架构集成项目

    Spring Cloud集成项目有很多,下面我们列举一下和Spring Cloud相关的优秀项目,我们的企业架构中用到了很多的优秀项目,说白了,也是站在巨人的肩膀上去整合的.在学习Spring Clo ...

  3. Spring Cloud分布式微服务云架构

    分布式.微服务.云架构 JAVA语言开发.跨平台.高性能.高可用.安全.服务化.模块化.組件化.驱动式开发模式 commonservice eurekaNetflix 云端服务发现,一个基于 REST ...

  4. Spring Boot + Spring Cloud 构建微服务系统(九):配置中心(Spring Cloud Config)

    技术背景 如今微服务架构盛行,在分布式系统中,项目日益庞大,子项目日益增多,每个项目都散落着各种配置文件,且随着服务的增加而不断增多.此时,往往某一个基础服务信息变更,都会导致一系列服务的更新和重启, ...

  5. 【SFA官方翻译】Spring WebFlux和Spring Cloud进行响应式微服务开发

    源码,修正一些错误: https://github.com/bigben0123/sample-spring-cloud-webflux 原创 SpringForAll社区 2018-05-18 作者 ...

  6. Spring Boot + Spring Cloud 构建微服务系统(十):配置中心(Spring Cloud Bus)

    技术背景 我们在上一篇讲到,Spring Boot程序只在启动的时候加载配置文件信息,这样在GIT仓库配置修改之后,虽然配置中心服务器能够读取最新的提交信息,但是配置中心客户端却不会重新读取,以至于不 ...

  7. Spring Boot + Spring Cloud 构建微服务系统(七):API服务网关(Zuul)

    技术背景 前面我们通过Ribbon或Feign实现了微服务之间的调用和负载均衡,那我们的各种微服务又要如何提供给外部应用调用呢. 当然,因为是REST API接口,外部客户端直接调用各个微服务是没有问 ...

  8. Spring Boot + Spring Cloud 构建微服务系统(四):容错机制和熔断(Hystrix)

    雪崩效应 在微服务架构中,由于服务众多,通常会涉及多个服务层级的调用,而一旦基础服务发生故障,很可能会导致级联故障,进而造成整个系统不可用,这种现象被称为服务雪崩效应.服务雪崩效应是一种因“服务提供者 ...

  9. Spring Boot + Spring Cloud 构建微服务系统(一):服务注册和发现(Consul)

    使用Consul提供注册和发现服务 什么是 Consul Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置.与其它分布式服务注册与发现的方案,Consul ...

随机推荐

  1. 标准会话对象——StandardSession

    Tomcat使用了一个StandardSession对象用来表示标准的会话结构,用来封装需要存储的状态信息.标准会话对象StandardSession实现了Session.Serializable.H ...

  2. C语言中如何写一个简单可移植而又足够随机的随机数生成器

    在C语言中标准库中的随机数产生函数的返回可能不是最优的,因为有些随机数生成器的低位并不随机,而另一些返回随机数的函数实现上又太复杂鸟.所以rand()%N并不是一个好方法,牛人给出的建议是使用: ra ...

  3. Mac Finder 里新建文本

    Mac Finder 里新建文本 首先吐槽下 Mac 的文件管理 Finder 真的是太弱了,之前没感觉 Windows 的资源管理器多厉害,但是和 Mac 的比起来真是堪称神器啊,果然牛逼与否还的看 ...

  4. 【模板】最近公共祖先(LCA)

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  5. centos 安装 vsftpd

    1.安装vsftpd yum -y install vsftpd 2.编辑vsftpd的配置文件 cp /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf- ...

  6. javascript学习笔记(四) Number 数字类型

    数字格式化方法toFixed().toExponential().toPrecision(),三个方法都四舍五入 toFixed() 方法指定小数位个数  toExponential() 方法 用科学 ...

  7. LINQ、Lambda与委托

    首先定义个Person类: public class Person { public string Name{get;set;} //姓名 public int Age{get;set;} //年龄 ...

  8. JS(原生js和jq方式)获取元素属性(自定义属性),删除属性(自定义属性)

    JS(原生js和jq方式)获取元素属性(自定义属性),删除属性(自定义属性) 以下内容: 一.获取元素的属性 二.设置元素的属性 三.删除元素的属性 一.获取元素的属性 1-原生JS 获取属性 .ge ...

  9. Python 爬取美团酒店信息

    事由:近期和朋友聊天,聊到黄山酒店事情,需要了解一下黄山的酒店情况,然后就想着用python 爬一些数据出来,做个参考 主要思路:通过查找,基本思路清晰,目标明确,仅仅爬取美团莫一地区的酒店信息,不过 ...

  10. WSL Windows Subsystem for Linux安装指南

    见官方文档: https://msdn.microsoft.com/en-us/commandline/wsl/install_guide