mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 02:08:43 +08:00 
			
		
		
		
	增加 Redis 分布式锁
This commit is contained in:
		| @@ -38,6 +38,8 @@ | ||||
| 1. Redis 监控:监控 Redis 数据库的使用情况,使用的 Redis Key 管理 | ||||
| 1. Java 监控:基于 Spring Boot Admin 实现 Java 应用的监控 | ||||
| 1. 链路追踪:基于 SkyWalking 实现性能监控,特别是链路的追踪 | ||||
| 1. 分布式锁:基于 Redis 实现分布式锁,满足并发场景 | ||||
| 1. 幂等组件:基于 Redis 实现幂等组件,解决重复请求问题 | ||||
|  | ||||
| ### 研发工具 | ||||
|  | ||||
| @@ -45,7 +47,6 @@ | ||||
| 1. 代码生成:前后端代码的生成(Java、Vue、SQL),支持 CRUD 下载 | ||||
| 1. 系统接口:基于 Swagger 自动生成相关的 RESTful API 接口文档 | ||||
| 1. 数据库文档:基于 Screw 自动生成数据库文档 | ||||
| 1. 幂等组件:基于 Redis 实现幂等组件,解决重复请求问题 | ||||
|  | ||||
| ## 在线体验 | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|   "local": { | ||||
|     "baseUrl": "http://127.0.0.1:8080/api", | ||||
|     "baseUrl": "http://127.0.0.1:48080/api", | ||||
|     "token": "test1" | ||||
|   } | ||||
| } | ||||
|   | ||||
							
								
								
									
										15
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								pom.xml
									
									
									
									
									
								
							| @@ -30,6 +30,10 @@ | ||||
|         <druid.version>1.2.4</druid.version> | ||||
|         <mybatis-plus.version>3.4.1</mybatis-plus.version> | ||||
|         <redisson.version>3.14.1</redisson.version> | ||||
|         <!-- Config 配置中心相关 --> | ||||
|         <apollo.version>1.7.0</apollo.version> | ||||
|         <!-- 服务保障相关 --> | ||||
|         <lock4j.version>2.2.0</lock4j.version> | ||||
|         <!-- 监控相关 --> | ||||
|         <skywalking.version>8.3.0</skywalking.version> | ||||
|         <spring-boot-admin.version>2.3.1</spring-boot-admin.version> | ||||
| @@ -125,7 +129,7 @@ | ||||
|         <dependency> | ||||
|             <groupId>com.ctrip.framework.apollo</groupId> | ||||
|             <artifactId>apollo-client</artifactId> <!-- 引入 Apollo Client 库,实现内嵌的配置中心 --> | ||||
|             <version>1.7.0</version> | ||||
|             <version>${apollo.version}</version> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- Job 定时任务相关 --> | ||||
| @@ -134,6 +138,13 @@ | ||||
|             <artifactId>spring-boot-starter-quartz</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- 服务保障相关 --> | ||||
|         <dependency> | ||||
|             <groupId>com.baomidou</groupId> | ||||
|             <artifactId>lock4j-redisson-spring-boot-starter</artifactId> | ||||
|             <version>${lock4j.version}</version> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- 监控相关 --> | ||||
|         <dependency> | ||||
|             <groupId>org.apache.skywalking</groupId> | ||||
| @@ -217,7 +228,7 @@ | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>cn.smallbun.screw</groupId> | ||||
|             <artifactId>screw-core</artifactId> | ||||
|             <artifactId>screw-core</artifactId> <!-- 实现数据库文档 --> | ||||
|             <version>${screw.version}</version> | ||||
|         </dependency> | ||||
|  | ||||
|   | ||||
| @@ -29,7 +29,8 @@ public interface GlobalErrorCodeConstants { | ||||
|     ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(500, "系统异常"); | ||||
|  | ||||
|     // ========== 自定义错误段 ========== | ||||
|     ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求"); | ||||
|     ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求,请稍后重试"); // 重复请求 | ||||
|     ErrorCode CONCURRENCY_REQUESTS = new ErrorCode(901, "请求失败,请稍后重试"); // 并发请求,不允许 | ||||
|  | ||||
|     ErrorCode UNKNOWN = new ErrorCode(999, "未知错误"); | ||||
|  | ||||
|   | ||||
| @@ -0,0 +1,23 @@ | ||||
| package cn.iocoder.dashboard.framework.lock4j.config; | ||||
|  | ||||
| import cn.hutool.core.util.ClassUtil; | ||||
| import cn.iocoder.dashboard.framework.lock4j.core.DefaultLockFailureStrategy; | ||||
| import cn.iocoder.dashboard.framework.lock4j.core.Lock4jRedisKeyConstants; | ||||
| import org.springframework.context.annotation.Bean; | ||||
| import org.springframework.context.annotation.Configuration; | ||||
|  | ||||
| @Configuration | ||||
| public class Lock4jConfiguration { | ||||
|  | ||||
|     static { | ||||
|         // 手动加载 Lock4jRedisKeyConstants 类,因为它不会被使用到 | ||||
|         // 如果不加载,会导致 Redis 监控,看到它的 Redis Key 枚举 | ||||
|         ClassUtil.loadClass(Lock4jRedisKeyConstants.class.getName()); | ||||
|     } | ||||
|  | ||||
|     @Bean | ||||
|     public DefaultLockFailureStrategy lockFailureStrategy() { | ||||
|         return new DefaultLockFailureStrategy(); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,20 @@ | ||||
| package cn.iocoder.dashboard.framework.lock4j.core; | ||||
|  | ||||
| import cn.iocoder.dashboard.common.exception.ServiceException; | ||||
| import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants; | ||||
| import com.baomidou.lock.LockFailureStrategy; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
|  | ||||
| /** | ||||
|  * 自定义获取锁失败策略,抛出 {@link cn.iocoder.dashboard.common.exception.ServiceException} 异常 | ||||
|  */ | ||||
| @Slf4j | ||||
| public class DefaultLockFailureStrategy implements LockFailureStrategy { | ||||
|  | ||||
|     @Override | ||||
|     public void onLockFailure(String key, long acquireTimeout, int acquireCount) { | ||||
|         log.debug("[onLockFailure][线程:{} 获取锁失败,key:{} 获取超时时长:{} ms]", Thread.currentThread().getName(), key, acquireTimeout); | ||||
|         throw new ServiceException(GlobalErrorCodeConstants.CONCURRENCY_REQUESTS); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,19 @@ | ||||
| package cn.iocoder.dashboard.framework.lock4j.core; | ||||
|  | ||||
| import cn.iocoder.dashboard.framework.redis.core.RedisKeyDefine; | ||||
| import org.redisson.api.RLock; | ||||
|  | ||||
| import static cn.iocoder.dashboard.framework.redis.core.RedisKeyDefine.KeyTypeEnum.HASH; | ||||
|  | ||||
| /** | ||||
|  * Lock4j Redis Key 枚举类 | ||||
|  * | ||||
|  * @author 芋道源码 | ||||
|  */ | ||||
| public interface Lock4jRedisKeyConstants { | ||||
|  | ||||
|     RedisKeyDefine LOCK4J = new RedisKeyDefine("分布式锁", | ||||
|             "lock4j:%s", // 参数来自 DefaultLockKeyBuilder 类 | ||||
|             HASH, RLock.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); // Redisson 的 Lock 锁,使用 Hash 数据结构 | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,4 @@ | ||||
| /** | ||||
|  * 分布式锁组件,使用 https://gitee.com/baomidou/lock4j 开源项目 | ||||
|  */ | ||||
| package cn.iocoder.dashboard.framework.lock4j; | ||||
| @@ -8,7 +8,7 @@ import java.time.Duration; | ||||
| import static cn.iocoder.dashboard.framework.redis.core.RedisKeyDefine.KeyTypeEnum.STRING; | ||||
|  | ||||
| /** | ||||
|  * Redis Key 枚举类 | ||||
|  * System Redis Key 枚举类 | ||||
|  * | ||||
|  * @author 芋道源码 | ||||
|  */ | ||||
|   | ||||
| @@ -0,0 +1,3 @@ | ||||
| ### 请求 /get-permission-info 接口 => 成功 | ||||
| GET {{baseUrl}}/tool/test-demo/get?id=1 | ||||
| Authorization: Bearer {{token}} | ||||
| @@ -1,5 +1,6 @@ | ||||
| package cn.iocoder.dashboard.modules.tool.controller.test; | ||||
|  | ||||
| import cn.hutool.core.thread.ThreadUtil; | ||||
| import cn.iocoder.dashboard.common.pojo.CommonResult; | ||||
| import cn.iocoder.dashboard.common.pojo.PageResult; | ||||
| import cn.iocoder.dashboard.framework.excel.core.util.ExcelUtils; | ||||
| @@ -8,6 +9,7 @@ import cn.iocoder.dashboard.modules.tool.controller.test.vo.*; | ||||
| import cn.iocoder.dashboard.modules.tool.convert.test.ToolTestDemoConvert; | ||||
| import cn.iocoder.dashboard.modules.tool.dal.dataobject.test.ToolTestDemoDO; | ||||
| import cn.iocoder.dashboard.modules.tool.service.test.ToolTestDemoService; | ||||
| import com.baomidou.lock.annotation.Lock4j; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiImplicitParam; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| @@ -21,6 +23,7 @@ import javax.validation.Valid; | ||||
| import java.io.IOException; | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
| import java.util.concurrent.TimeUnit; | ||||
|  | ||||
| import static cn.iocoder.dashboard.common.pojo.CommonResult.success; | ||||
| import static cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateTypeEnum.EXPORT; | ||||
| @@ -62,7 +65,11 @@ public class ToolTestDemoController { | ||||
|     @ApiOperation("获得测试示例") | ||||
|     @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) | ||||
|     @PreAuthorize("@ss.hasPermission('tool:test-demo:query')") | ||||
|     @Lock4j // 分布式锁 | ||||
|     public CommonResult<ToolTestDemoRespVO> getTestDemo(@RequestParam("id") Long id) { | ||||
|         if (true) { // 测试分布式锁 | ||||
|             ThreadUtil.sleep(5, TimeUnit.SECONDS); | ||||
|         } | ||||
|         ToolTestDemoDO testDemo = testDemoService.getTestDemo(id); | ||||
|         return success(ToolTestDemoConvert.INSTANCE.convert(testDemo)); | ||||
|     } | ||||
|   | ||||
| @@ -81,6 +81,13 @@ apollo: | ||||
|     username: ${spring.datasource.username} | ||||
|     password: ${spring.datasource.password} | ||||
|  | ||||
| --- #################### 服务保障相关配置 #################### | ||||
|  | ||||
| # Lock4j 配置项 | ||||
| lock4j: | ||||
|   acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒 | ||||
|   expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒 | ||||
|  | ||||
| --- #################### 监控相关配置 #################### | ||||
|  | ||||
| # Actuator 监控端点的配置项 | ||||
|   | ||||
| @@ -81,6 +81,13 @@ apollo: | ||||
|     username: ${spring.datasource.username} | ||||
|     password: ${spring.datasource.password} | ||||
|  | ||||
| --- #################### 服务保障相关配置 #################### | ||||
|  | ||||
| # Lock4j 配置项 | ||||
| lock4j: | ||||
|   acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒 | ||||
|   expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒 | ||||
|  | ||||
| --- #################### 监控相关配置 #################### | ||||
|  | ||||
| # Actuator 监控端点的配置项 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV