在SpringBoot中如何实现分布式的单例对象?
mhr18 2024-12-04 13:27 19 浏览 0 评论
所谓的分布式单例对象是指在分布式系统中,多个分布式节点共享一个对象实例,也就是说在系统的任意给定时刻只能有一个节点持有该对象的唯一的实例对象,在分布式场景中想要实现一个分布式单例对象其核心关键点就是在于如何保证分布式锁和对象的高可用性。下面我们就来看看如何设计一个分布式单例对象的实现。
设计思路
分布式锁
在分布式场景下,我们可以通过分布式锁机制确保在多节点并发环境下,只有一个节点能实例化单例对象。而我们比较常见的分布式锁技术包括Redis、Zookeeper、Etcd等。
实例化控制
在分布式锁的保护下要确保所有节点中,只有一个节点执行实例化代码,其它节点在需要时访问已经生成的实例。
高可用
当然,如果生成单例对象的节点失效,这个时候就需要保证有其他节点接管并重新创建单例对象。所以需要一种“领导者”选举机制,使得当当前持有对象的节点失效时,其他节点能够发现并重新初始化单例对象。
缓存
通过本地缓存机制缓存该对象的引用,减少不必要的分布式锁开销,提高访问性能。
使用Spring Boot实现
下面,我们通过使用Redis实现分布式锁,并结合Spring Boot来实现分布式单实例实现。
首先,我们需要在Spring Boot项目中引入Redis依赖和Spring Boot Starter依赖配置,如下所示。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
在application.yml中配置Redis连接信息
spring:
redis:
host: localhost
port: 6379
password: ""
实现分布式锁
Redis分布式锁可以通过SETNX命令实现,如下所示,我们可以在Spring中通过StringRedisTemplate来操作Redis,实现分布式锁操作。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class RedisLock {
@Autowired
private StringRedisTemplate redisTemplate;
public boolean tryLock(String key, String value, long timeout, TimeUnit timeUnit) {
return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value, timeout, timeUnit));
}
public void unlock(String key, String value) {
String currentValue = redisTemplate.opsForValue().get(key);
if (value.equals(currentValue)) {
redisTemplate.delete(key);
}
}
}
- tryLock:通过setIfAbsent方法尝试获取锁,若获取成功返回true,否则返回false。
- unlock:通过比对锁的唯一值,确保锁是由当前节点持有时才进行释放,避免误删其他节点的锁。
在锁的创建过程中,需要考虑到由于网络波动等原因,可能导致锁失效。所以可以在锁里面加入自动续约机制,保证在锁持有期间不会因锁过期而释放。为了避免Redis单点问题,可以引入Redis集群来解决高可用的问题。或者可以引入Zookeeper或Etcd来简化锁管理和Leader选举,这两种工具的“临时节点”特性天然支持分布式单例实现。
单例对象实现
接下来,就是创建单例对象的过程,创建一个分布式单例类DistributedSingleton,其初始化会使用RedisLock来确保只在一个节点上创建,如下所示。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;
@Component
public class DistributedSingleton {
private static volatile DistributedSingleton instance;
private static final String LOCK_KEY = "distributed_singleton_lock";
private static final String LOCK_VALUE = "singleton_instance_lock";
@Autowired
private RedisLock redisLock;
private DistributedSingleton() {
// 私有构造函数确保不能直接创建实例
}
public static DistributedSingleton getInstance() {
if (instance == null) {
synchronized (DistributedSingleton.class) {
if (instance == null) {
instance = new DistributedSingleton();
}
}
}
return instance;
}
@PostConstruct
public void init() {
if (instance == null) {
boolean lockAcquired = redisLock.tryLock(LOCK_KEY, LOCK_VALUE, 30, TimeUnit.SECONDS);
if (lockAcquired) {
try {
instance = new DistributedSingleton();
System.out.println("Singleton instance created by " + Thread.currentThread().getName());
} finally {
redisLock.unlock(LOCK_KEY, LOCK_VALUE);
}
}
}
}
public void performAction() {
System.out.println("Performing action in singleton instance: " + instance);
}
}
getInstance方法中使用双重检查锁(DCL)来确保单例的线程安全性。@PostConstruct注解的init方法在实例创建后会尝试获取分布式锁,成功获取后进行实例化。
接下来,我们可以在Controller中测试分布式单例对象的创建,如下所示。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SingletonController {
@Autowired
private DistributedSingleton distributedSingleton;
@GetMapping("/test-singleton")
public String testSingleton() {
distributedSingleton.performAction();
return "Singleton tested!";
}
}
在多台机器上运行应用或者在单台机器上启动多个端口。访问/test-singleton接口,观察控制台日志,确保只有一个实例会输出创建日志。如果该实例宕机,其他实例可根据Redis锁自动接管并重新生成单例对象。
总结
这种基于Redis分布式锁的单例实现方式适合在分布式系统中保证对象唯一性。结合Spring Boot,实现了系统级别的分布式单例,适用于需要跨节点共享的状态控制和管理场景。
相关推荐
- Dubai's AI Boom Lures Global Tech as Emirate Reinvents Itself as Middle East's Silicon Gateway
-
AI-generatedimageAsianFin--Dubaiisrapidlytransformingitselffromadesertoilhubintoaglob...
- OpenAI Releases o3-pro, Cuts o3 Prices by 80% as Deal with Google Cloud Reported to Make for Compute Needs
-
TMTPOST--OpenAIisescalatingthepricewarinlargelanguagemodel(LLM)whileseekingpartnershi...
- 黄仁勋说AI Agent才是未来!但究竟有些啥影响?
-
,抓住风口(iOS用户请用电脑端打开小程序)本期要点:详解2025年大热点你好,我是王煜全,这里是王煜全要闻评论。最近,有个词被各个科技大佬反复提及——AIAgent,智能体。黄仁勋在CES展的发布...
- 商城微服务项目组件搭建(五)——Kafka、Tomcat等安装部署
-
1、本文属于mini商城系列文档的第0章,由于篇幅原因,这篇文章拆成了6部分,本文属于第5部分2、mini商城项目详细文档及代码见CSDN:https://blog.csdn.net/Eclipse_...
- Python+Appium环境搭建与自动化教程
-
以下是保姆级教程,手把手教你搭建Python+Appium环境并实现简单的APP自动化测试:一、环境搭建(Windows系统)1.安装Python访问Python官网下载最新版(建议...
- 零配置入门:用VSCode写Java代码的正确姿
-
一、环境准备:安装JDK,让电脑“听懂”Java目标:安装Java开发工具包(JDK),配置环境变量下载JDKJava程序需要JDK(JavaDevelopmentKit)才能运行和编译。以下是两...
- Mycat的搭建以及配置与启动(mycat2)
-
1、首先开启服务器相关端口firewall-cmd--permanent--add-port=9066/tcpfirewall-cmd--permanent--add-port=80...
- kubernetes 部署mysql应用(k8s mysql部署)
-
这边仅用于测试环境,一般生产环境mysql不建议使用容器部署。这里假设安装mysql版本为mysql8.0.33一、创建MySQL配置(ConfigMap)#mysql-config.yaml...
- Spring Data Jpa 介绍和详细入门案例搭建
-
1.SpringDataJPA的概念在介绍SpringDataJPA的时候,我们首先认识下Hibernate。Hibernate是数据访问解决技术的绝对霸主,使用O/R映射(Object-Re...
- 量子点格棋上线!“天衍”邀您执子入局
-
你是否能在策略上战胜量子智能?这不仅是一场博弈更是一次量子智力的较量——量子点格棋正式上线!试试你能否赢下这场量子智局!游戏玩法详解一笔一画间的策略博弈游戏目标:封闭格子、争夺领地点格棋的基本目标是利...
- 美国将与阿联酋合作建立海外最大的人工智能数据中心
-
当地时间5月15日,美国白宫宣布与阿联酋合作建立人工智能数据中心园区,据称这是美国以外最大的人工智能园区。阿布扎比政府支持的阿联酋公司G42及多家美国公司将在阿布扎比合作建造容量为5GW的数据中心,占...
- 盘后股价大涨近8%!甲骨文的业绩及指引超预期?
-
近期,美股的AI概念股迎来了一波上升行情,微软(MSFT.US)频创新高,英伟达(NVDA.US)、台积电(TSM.US)、博通(AVGO.US)、甲骨文(ORCL.US)等多股亦出现显著上涨。而从基...
- 甲骨文预计新财年云基础设施营收将涨超70%,盘后一度涨8% | 财报见闻
-
甲骨文(Oracle)周三盘后公布财报显示,该公司第四财季业绩超预期,虽然云基建略微逊于预期,但管理层预计2026财年云基础设施营收预计将增长超过70%,同时资本支出继上年猛增三倍后,新财年将继续增至...
- Springboot数据访问(整合MongoDB)
-
SpringBoot整合MongoDB基本概念MongoDB与我们之前熟知的关系型数据库(MySQL、Oracle)不同,MongoDB是一个文档数据库,它具有所需的可伸缩性和灵活性,以及所需的查询和...
- Linux环境下,Jmeter压力测试的搭建及报错解决方法
-
概述 Jmeter最早是为了测试Tomcat的前身JServ的执行效率而诞生的。到目前为止,它的最新版本是5.3,其测试能力也不再仅仅只局限于对于Web服务器的测试,而是涵盖了数据库、JM...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- Dubai's AI Boom Lures Global Tech as Emirate Reinvents Itself as Middle East's Silicon Gateway
- OpenAI Releases o3-pro, Cuts o3 Prices by 80% as Deal with Google Cloud Reported to Make for Compute Needs
- 黄仁勋说AI Agent才是未来!但究竟有些啥影响?
- 商城微服务项目组件搭建(五)——Kafka、Tomcat等安装部署
- Python+Appium环境搭建与自动化教程
- 零配置入门:用VSCode写Java代码的正确姿
- Mycat的搭建以及配置与启动(mycat2)
- kubernetes 部署mysql应用(k8s mysql部署)
- Spring Data Jpa 介绍和详细入门案例搭建
- 量子点格棋上线!“天衍”邀您执子入局
- 标签列表
-
- oracle位图索引 (74)
- oracle批量插入数据 (65)
- oracle事务隔离级别 (59)
- oracle 空为0 (51)
- oracle主从同步 (56)
- oracle 乐观锁 (53)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)