Spring Boot实战:基于策略模式+代理模式手写幂等性注解组件
一、为什么需要幂等性?
核心定义:在分布式系统中,一个操作无论执行一次还是多次,最终结果都保持一致。
典型场景:
- 用户重复点击提交按钮
- 网络抖动导致的请求重试
- 消息队列的重复消费
- 支付系统的回调通知
不处理幂等的风险:
- 重复创建订单导致资金损失
- 库存超卖引发资损风险
- 用户数据重复插入破坏业务逻辑
二、实现步骤分解
1. 定义幂等注解
/*** 幂等注解** @author dyh*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {/*** 幂等的超时时间,默认为 1 秒** 注意,如果执行时间超过它,请求还是会进来*/int timeout() default 1;/*** 时间单位,默认为 SECONDS 秒*/TimeUnit timeUnit() default TimeUnit.SECONDS;/*** 提示信息,正在执行中的提示*/String message() default "重复请求,请稍后重试";/*** 使用的 Key 解析器** @see DefaultIdempotentKeyResolver 全局级别* @see UserIdempotentKeyResolver 用户级别* @see ExpressionIdempotentKeyResolver 自定义表达式,通过 {@link #keyArg()} 计算*/Class<? extends IdempotentKeyResolver> keyResolver() default DefaultIdempotentKeyResolver.class;/*** 使用的 Key 参数*/String keyArg() default "";/*** 删除 Key,当发生异常时候** 问题:为什么发生异常时,需要删除 Key 呢?* 回答:发生异常时,说明业务发生错误,此时需要删除 Key,避免下次请求无法正常执行。** 问题:为什么不搞 deleteWhenSuccess 执行成功时,需要删除 Key 呢?* 回答:这种情况下,本质上是分布式锁,推荐使用 @Lock4j 注解*/boolean deleteKeyWhenException() default true;}
2. 设计Key解析器接口
/*** 幂等 Key 解析器接口** @author dyh*/
public interface IdempotentKeyResolver {/*** 解析一个 Key** @param idempotent 幂等注解* @param joinPoint AOP 切面* @return Key*/String resolver(JoinPoint joinPoint, Idempotent idempotent);}
3. 实现三种核心策略
- 默认策略:方法签名+参数MD5(防全局重复)
- 用户策略:用户ID+方法特征(防用户重复)
- 表达式策略:SpEL动态解析参数(灵活定制)
3.1 默认策略
/*** 默认(全局级别)幂等 Key 解析器,使用方法名 + 方法参数,组装成一个 Key** 为了避免 Key 过长,使用 MD5 进行“压缩”** @author dyh*/
public class DefaultIdempotentKeyResolver implements IdempotentKeyResolver {/*** 核心方法:生成幂等Key(基于方法特征+参数内容)* @param joinPoint AOP切入点对象,包含方法调用信息* @param idempotent 方法上的幂等注解对象* @return 生成的唯一幂等Key(32位MD5哈希值)*/@Overridepublic String resolver(JoinPoint joinPoint, Idempotent idempotent) {// 获取方法完整签名(格式:返回值类型 类名.方法名(参数类型列表))// 示例:String com.example.UserService.createUser(Long,String)String methodName = joinPoint.getSignature().toString();// 将方法参数数组拼接为字符串(用逗号分隔)// 示例:参数是 [123, "张三"] 将拼接为 "123,张三"String argsStr = StrUtil.join(",", joinPoint.getArgs());// 将方法签名和参数字符串合并后计算MD5// 目的:将可能很长的字符串压缩为固定长度,避免Redis Key过长return SecureUtil.md5(methodName + argsStr);}}
3.2 用户策略
/*** 用户级别的幂等 Key 解析器,使用方法名 + 方法参数 + userId + userType,组装成一个 Key* <p>* 为了避免 Key 过长,使用 MD5 进行“压缩”** @author dyh*/
public class UserIdempotentKeyResolver implements IdempotentKeyResolver {/*** 生成用户级别的幂等Key** @param joinPoint AOP切入点对象(包含方法调用信息)* @param idempotent 方法上的幂等注解* @return 基于用户维度的32位MD5哈希值* <p>* 生成逻辑分四步:* 1. 获取方法签名 -> 标识具体方法* 2. 拼接参数值 -> 标识操作数据* 3. 获取用户身份 -> 隔离用户操作* 4. MD5哈希计算 -> 压缩存储空间*/@Overridepublic String resolver(JoinPoint joinPoint, Idempotent idempotent) {// 步骤1:获取方法唯一标识(格式:返回类型 类名.方法名(参数类型列表))// 示例:"void com.service.UserService.updatePassword(Long,String)"String methodName = joinPoint.getSignature().toString();// 步骤2:将方法参数转换为逗号分隔的字符串// 示例:参数是 [1001, "新密码"] 会拼接成 "1001,新密码"String argsStr = StrUtil.join(",", joinPoint.getArgs());// 步骤3:从请求上下文中获取当前登录用户ID// 注意:需确保在Web请求环境中使用,未登录时可能返回nullLong userId = WebFrameworkUtils.getLoginUserId();// 步骤4:获取当前用户类型(例如:0-普通用户,1-管理员)// 作用:区分不同权限用户的操作Integer userType = WebFrameworkUtils.getLoginUserType();// 步骤5:将所有要素拼接后生成MD5哈希值// 输入示例:"void updatePassword()1001,新密码1231"// 输出示例:"d3d9446802a44259755d38e6d163e820"return SecureUtil.md5(methodName + argsStr + userId + userType);}
}
3.3 表达式策略
/*** 基于 Spring EL 表达式,** @author dyh*/
public class ExpressionIdempotentKeyResolver implements IdempotentKeyResolver {// 参数名发现器:用于获取方法的参数名称(如:userId, orderId)// 为什么用LocalVariableTable:因为编译后默认不保留参数名,需要这个工具读取调试信息private final ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();// 表达式解析器:专门解析Spring EL表达式// 为什么用Spel:Spring官方标准,支持复杂表达式语法private final ExpressionParser expressionParser = new SpelExpressionParser();/*** 核心方法:解析生成幂等Key** @param joinPoint AOP切入点(包含方法调用信息)* @param idempotent 方法上的幂等注解* @return 根据表达式生成的唯一Key*/@Overridepublic String resolver(JoinPoint joinPoint, Idempotent idempotent) {// 步骤1:获取当前执行的方法对象Method method = getMethod(joinPoint);// 步骤2:获取方法参数值数组(例如:[订单对象, 用户对象])Object[] args = joinPoint.getArgs();// 步骤3:获取方法参数名数组(例如:["order", "user"])String[] parameterNames = this.parameterNameDiscoverer.getParameterNames(method);// 步骤4:创建表达式上下文(相当于给表达式提供变量环境)StandardEvaluationContext evaluationContext = new StandardEvaluationContext();// 步骤5:将参数名和参数值绑定到上下文(让表达式能识别#order这样的变量)if (ArrayUtil.isNotEmpty(parameterNames)) {for (int i = 0; i < parameterNames.length; i++) {// 例如:将"order"参数名和实际的Order对象绑定evaluationContext.setVariable(parameterNames[i], args[i]);}}// 步骤6:解析注解中的表达式(例如:"#order.id")Expression expression = expressionParser.parseExpression(idempotent.keyArg());// 步骤7:执行表达式计算(例如:从order对象中取出id属性值)return expression.getValue(evaluationContext, String.class);}/*** 辅助方法:获取实际执行的方法对象* 为什么需要这个方法:处理Spring AOP代理接口的情况** @param point AOP切入点* @return 实际被调用的方法对象*/private static Method getMethod(JoinPoint point) {// 情况一:方法直接定义在类上(非接口方法)MethodSignature signature = (MethodSignature) point.getSignature();Method method = signature.getMethod();if (!method.getDeclaringClass().isInterface()) {return method; // 直接返回当前方法}// 情况二:方法定义在接口上(需要获取实现类的方法)try {// 通过反射获取目标类(实际实现类)的方法// 例如:UserService接口的create方法 -> UserServiceImpl的create方法return point.getTarget().getClass().getDeclaredMethod(point.getSignature().getName(), // 方法名method.getParameterTypes()); // 参数类型} catch (NoSuchMethodException e) {// 找不到方法时抛出运行时异常(通常意味着代码结构有问题)throw new RuntimeException("方法不存在: " + method.getName(), e);}}
}
4. 编写AOP切面
/*** 拦截声明了 {@link Idempotent} 注解的方法,实现幂等操作* 幂等切面处理器** 功能:拦截被 @Idempotent 注解标记的方法,通过Redis实现请求幂等性控制* 流程:* 1. 根据配置的Key解析策略生成唯一标识* 2. 尝试在Redis中设置该Key(SETNX操作)* 3. 若Key已存在 → 抛出重复请求异常* 4. 若Key不存在 → 执行业务逻辑* 5. 异常时根据配置决定是否删除Key** @author dyh*/
@Aspect // 声明为AOP切面类
@Slf4j // 自动生成日志对象public class IdempotentAspect {/*** Key解析器映射表(Key: 解析器类型,Value: 解析器实例)* 示例:* DefaultIdempotentKeyResolver.class → DefaultIdempotentKeyResolver实例* ExpressionIdempotentKeyResolver.class → ExpressionIdempotentKeyResolver实例*/private final Map<Class<? extends IdempotentKeyResolver>, IdempotentKeyResolver> keyResolvers;/*** Redis操作工具类(处理幂等Key的存储)*/private final IdempotentRedisDAO idempotentRedisDAO;/*** 构造方法(依赖注入)* @param keyResolvers 所有Key解析器的Spring Bean集合* @param idempotentRedisDAO Redis操作DAO*/public IdempotentAspect(List<IdempotentKeyResolver> keyResolvers, IdempotentRedisDAO idempotentRedisDAO) {// 将List转换为Map,Key是解析器的Class类型this.keyResolvers = CollectionUtils.convertMap(keyResolvers, IdempotentKeyResolver::getClass);this.idempotentRedisDAO = idempotentRedisDAO;}/*** 环绕通知:拦截被@Idempotent注解的方法* @param joinPoint 切入点(包含方法、参数等信息)* @param idempotent 方法上的@Idempotent注解实例* @return 方法执行结果* @throws Throwable 可能抛出的异常** 执行流程:* 1. 获取Key解析器 → 2. 生成唯一Key → 3. 尝试锁定 → 4. 执行业务 → 5. 异常处理*/@Around(value = "@annotation(idempotent)") // 切入带有@Idempotent注解的方法public Object aroundPointCut(ProceedingJoinPoint joinPoint, Idempotent idempotent) throws Throwable {// 步骤1:根据注解配置获取对应的Key解析器IdempotentKeyResolver keyResolver = keyResolvers.get(idempotent.keyResolver());// 断言确保解析器存在(找不到说明Spring容器初始化有问题)Assert.notNull(keyResolver, "找不到对应的 IdempotentKeyResolver");// 步骤2:使用解析器生成唯一Key(例如:MD5(方法签名+参数))String key = keyResolver.resolver(joinPoint, idempotent);// 步骤3:尝试在Redis中设置Key(原子性操作)// 参数说明:// key: 唯一标识// timeout: 过期时间(通过注解配置)// timeUnit: 时间单位(通过注解配置)boolean success = idempotentRedisDAO.setIfAbsent(key, idempotent.timeout(), idempotent.timeUnit());// 步骤4:处理重复请求if (!success) {// 记录重复请求日志(方法签名 + 参数)log.info("[幂等拦截] 方法({}) 参数({}) 存在重复请求",joinPoint.getSignature().toString(),joinPoint.getArgs());// 抛出业务异常(携带注解中配置的错误提示信息)throw new ServiceException(GlobalErrorCodeConstants.REPEATED_REQUESTS.getCode(),idempotent.message());}try {// 步骤5:执行原始业务方法return joinPoint.proceed();} catch (Throwable throwable) {// 步骤6:异常处理(参考美团GTIS设计)// 配置删除策略:当deleteKeyWhenException=true时,删除Key允许重试if (idempotent.deleteKeyWhenException()) {// 记录删除操作日志(实际生产可添加更详细日志)log.debug("[幂等异常处理] 删除Key: {}", key);idempotentRedisDAO.delete(key);}// 继续抛出异常(由全局异常处理器处理)throw throwable;}}
}
5. 实现Redis原子操作
/*** 幂等 Redis DAO** @author dyh*/
@AllArgsConstructor
public class IdempotentRedisDAO {/*** 幂等操作** KEY 格式:idempotent:%s // 参数为 uuid* VALUE 格式:String* 过期时间:不固定*/private static final String IDEMPOTENT = "idempotent:%s";private final StringRedisTemplate redisTemplate;public Boolean setIfAbsent(String key, long timeout, TimeUnit timeUnit) {String redisKey = formatKey(key);return redisTemplate.opsForValue().setIfAbsent(redisKey, "", timeout, timeUnit);}public void delete(String key) {String redisKey = formatKey(key);redisTemplate.delete(redisKey);}private static String formatKey(String key) {return String.format(IDEMPOTENT, key);}}
6. 自动装配
/*** @author dyh* @date 2025/4/17 18:08*/
@AutoConfiguration(after = DyhRedisAutoConfiguration.class)
public class DyhIdempotentConfiguration {@Beanpublic IdempotentAspect idempotentAspect(List<IdempotentKeyResolver> keyResolvers, IdempotentRedisDAO idempotentRedisDAO) {return new IdempotentAspect(keyResolvers, idempotentRedisDAO);}@Beanpublic IdempotentRedisDAO idempotentRedisDAO(StringRedisTemplate stringRedisTemplate) {return new IdempotentRedisDAO(stringRedisTemplate);}// ========== 各种 IdempotentKeyResolver Bean ==========@Beanpublic DefaultIdempotentKeyResolver defaultIdempotentKeyResolver() {return new DefaultIdempotentKeyResolver();}@Beanpublic UserIdempotentKeyResolver userIdempotentKeyResolver() {return new UserIdempotentKeyResolver();}@Beanpublic ExpressionIdempotentKeyResolver expressionIdempotentKeyResolver() {return new ExpressionIdempotentKeyResolver();}}
三、核心设计模式解析
1. 策略模式(核心设计)
应用场景:多种幂等Key生成策略的动态切换
代码体现:
// 策略接口
public interface IdempotentKeyResolver {String resolver(JoinPoint joinPoint, Idempotent idempotent);
}// 具体策略实现
public class DefaultIdempotentKeyResolver implements IdempotentKeyResolver {@Overridepublic String resolver(...) { /* MD5(方法+参数) */ }
}public class ExpressionIdempotentKeyResolver implements IdempotentKeyResolver {@Overridepublic String resolver(...) { /* SpEL解析 */ }
}
UML图示:
2. 代理模式(AOP实现)
应用场景:通过动态代理实现无侵入的幂等控制
代码体现:
@Aspect
public class IdempotentAspect {@Around("@annotation(idempotent)") // 切入点表达式public Object around(...) {// 通过代理对象控制原方法执行return joinPoint.proceed(); }
}
执行流程:
客户端调用 → 代理对象拦截 → 执行幂等校验 → 调用真实方法
四、这样设计的好处
- 业务解耦
- 幂等逻辑与业务代码完全分离
- 通过注解实现声明式配置
- 灵活扩展
- 新增Key策略只需实现接口
- 支持自定义SpEL表达式
- 高可靠性
- Redis原子操作防并发问题
- 异常时自动清理Key(可配置)
- 性能优化
- MD5压缩减少Redis存储压力
- 细粒度锁控制(不同Key互不影响)
- 易用性
- 开箱即用的starter组件
- 三种内置策略覆盖主流场景
五、使用示例
@Idempotent(keyResolver = UserIdempotentKeyResolver.class,timeout = 10,message = "请勿重复提交订单"
)
public void createOrder(OrderDTO dto) {// 业务逻辑
}
相关文章:
Spring Boot实战:基于策略模式+代理模式手写幂等性注解组件
一、为什么需要幂等性? 核心定义:在分布式系统中,一个操作无论执行一次还是多次,最终结果都保持一致。 典型场景: 用户重复点击提交按钮网络抖动导致的请求重试消息队列的重复消费支付系统的回调通知 不处理幂等的风…...
【.net core】【watercloud】数据库连接报错问题
错误信息: 中文提示 : 连接数据库过程中发生错误,检查服务器是否正常连接字符串是否正确,错误信息:Cannot Open when State is Connecting.DbType"MySql";ConfigId"0". English Message : Connection open …...
69. x 的平方根
目录 一、问题描述 二、解题思路 三、代码 四、复杂度分析 一、问题描述 给你一个非负整数 x ,计算并返回 x 的 算术平方根 。 由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。 注意:不允许使用任何内置指数…...
计算机网络基础概论
计算机网络基础概论 目录 一、网络基本概念 1.1. 网络 1.2 互联网 1.3 ip地址 1.3.1 作用 1.3.2 分类 1.4 MAC地址 1.4.1 MAC地址与 IP 地址的关系 1.5 网络协议 二、网络分层模型 2.1 物理层 2.2 数据链路层 2.3 网络层 2.4 传输层 2.5 会话层 2.6 表示层 2.7…...
京东3D空间视频生成技术探索与应用
1. 背景 近年来,随着社交媒体、流媒体平台以及XR设备的快速发展,沉浸式3D空间视频的需求迅猛增长,尤其是在短视频、直播和电影领域,正在重新定义观众的观看体验。2023年,苹果公司发布的空间视频技术为这一趋势注入了新…...
吉利矩阵(DFS)
所有元素为非负整数,且各行各列的元素和都等于 7 的 33 方阵称为 “吉利矩阵”,因为这样的矩阵一共有 666 种。 本题就请你统计一下,各行各列的元素和都等于 5 的 33 方阵一共有多少种? 思路:统计方法数,…...
突破反爬限制的智能数据采集实战 —— 面向中小企业的高效信息监控方案
在当前数据驱动的商业环境中,如何高效、稳定地获取网络数据,已成为众多中小企业进行市场洞察、竞品监测与品牌舆情管理的关键能力。本文将分享一个基于先进API技术构建的社交媒体热点监控系统,聚焦实际应用场景,展示如何在合规前提…...
从0到1:让AI赋能计算机的全流程实践指南
🎁个人主页:User_芊芊君子 🎉欢迎大家点赞👍评论📝收藏⭐文章 🔍系列专栏:AI 【前言】 在数字化浪潮席卷全球的今天,AI(人工智能)早已不是科幻电影中的虚构概…...
IntelliJ IDEA 2025.1 发布 ,默认 K2 模式 | Android Studio 也将跟进
2025.1 版本已经发布,在此之前我们就聊过该版本的 《Terminal 又发布全新重构版本》,而现在 2025.1 中的 K2 模式也成为了默认选项。 可以预见,这个版本可能会包含不少大坑,为下个 Android Studio 祈祷。 首先有一点可以确定&…...
MCP、A2A、Function Calling:AI架构设计的三驾马车
随着AI浪潮的到来,各种技术和概念也层出不穷,作为技术人应该第一时间掌握其核心概念与原理,以便于在工作和交流中傻傻分不清楚,本文主要就最近大家提及比较多的MCP、A2A和Function Call做下普及与区分 在当今快速发展的AI领域&a…...
NO.96十六届蓝桥杯备战|图论基础-多源最短路|Floyd|Clear And Present Danger|灾后重建|无向图的最小环问题(C++)
多源最短路:即图中每对顶点间的最短路径 floyd算法本质是动态规划,⽤来求任意两个结点之间的最短路,也称插点法。通过不断在两点之间加⼊新的点,来更新最短路。 适⽤于任何图,不管有向⽆向,边权正负&…...
OpenHarmony - 小型系统内核(LiteOS-A)(六)
OpenHarmony - 小型系统内核(LiteOS-A)(六) 七、文件系统 支持的文件系统 FAT 基本概念 FAT文件系统是File Allocation Table(文件配置表)的简称,主要包括DBR区、FAT区、DATA区三个区域。其…...
“星睿O6” AI PC开发套件评测 - Windows on Arm 安装指南和性能测评
引言 Radxa联合此芯科技和安谋科技推出全新的"星睿O6"迷你 ITX 主板。该系统搭载了 CIX P1(CD8180)12 核 Armv9 处理器,拥有高达30T算力的NPU和高性能的GPU,最高配备64GB LPDDR内存,并提供了如 5GbE、HDMI …...
JS实现RSA加密
目录 目标 环境 实现RSA加解密 计算RSA加密允许的最大字节长度 目标 使用JS实现RSA加密解密。计算RSA加密允许的最大字节长度。 环境 node-rsa 实现RSA加解密 const NodeRSA require(node-rsa);function getKey() {const keyLength512// 创建 RSA 密钥对const key new …...
Seata方案详细
Seata(Simple Extensible Autonomous Transaction Architecture)是阿里开源的分布式事务解决方案,支持多种事务模式,提供一站式的事务管理能力。以下是其核心原理、模式及实践的详细解析: 一、Seata核心架构与角色 Se…...
深入了解v-model的原理:v-model拆分为value属性和input事件,表单类组件的封装并用v-model简化代码
文章目录 1.v-model的原理1.1.验证:在input文本输入框中不使用v-model实现双向数据绑定1.2.验证:v-model在下拉菜单中的拆分 2.表单类组件的封装2.1.原理或步骤2.2.示例:表单类组件封装之下拉菜单select的封装 3.使用v-model简化代码完整代码 4.拓展示例:完成input文本输入框的…...
设计模式每日硬核训练 Day 14:组合模式(Composite Pattern)完整讲解与实战应用
🔄 回顾 Day 13:桥接模式小结 在 Day 13 中,我们学习了桥接模式(Bridge Pattern): 用于将“抽象”与“实现”分离,适用于双维度变化场景(如图形类型 渲染方式)。它强调…...
RMSIN论文阅读
自适应旋转卷积 (ARC)是否可以换成可变形卷积 研究背景 指向性遥感图像分割(RRSIS):旨在根据文本描述实现遥感图像中目标对象的像素级定位 像素级定位:像素级定位指的是在图像中对目标对象的每个像素进行准确的定位和标记。这意味…...
【音视频】FLV格式分析
FLV概述 FLV(Flash Video)是Adobe公司推出的⼀种流媒体格式,由于其封装后的⾳视频⽂件体积⼩、封装简单等特点,⾮常适合于互联⽹上使⽤。⽬前主流的视频⽹站基本都⽀持FLV。采⽤FLV格式封装的⽂件后缀为.flv。 FLV封装格式是由⼀个⽂件头(file header)和…...
华为OD机试真题——最小的调整次数/特异性双端队列(2025A卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现
2025 A卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C、C语言、GO六种语言的最佳实现方式! 2025华为OD真题目录全流程解析/备考攻略/经验分享 华为OD机试真题《最小的调…...
华为OD机试真题——统计匹配的二元组个数(2025A卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现
2025 A卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C、C语言、GO六种语言的最佳实现方式! 2025华为OD真题目录全流程解析/备考攻略/经验分享 华为OD机试真题《统计匹配…...
4.16学习总结
完成134. 加油站 - 力扣(LeetCode)算法题 学习了filewriter的相关方法,了解了字符流的底层原理...
java面试篇 4.9
目录 mybatis: 1、mybatis的执行流程 2、mybatis是否支持延迟加载? 当我们需要去开启全局的懒加载时: 3、mybatis的一级和二级缓存 微服务 1、springcloud五大组件有哪些 2、服务注册和发现是什么意思?springcloud如何实现…...
子函数嵌套的意义——以“颜色排序”为例(Python)
多一层缩进精减参数传递,参数少平铺书代码写更佳。 笔记模板由python脚本于2025-04-16 11:52:53创建,本篇笔记适合喜欢子函数嵌套结构代码形式的coder翻阅。 【学习的细节是欢悦的历程】 博客的核心价值:在于输出思考与经验,而不仅…...
Python深度学习实现验证码识别全攻略
放在前面 Python深度学习实现验证码识别全攻略 Python深度学习实现验证码识别全攻略 在网络安全领域,验证码作为人机区分的关键防线,广泛应用于登录、注册等场景。随着技术演进,验证码样式愈发复杂,传统识别手段力不从心&#…...
【Linux】su、su-、sudo、sudo -i、sudo su - 命令有什么区别?分别适用什么场景?
目录 su su- sudo sudo -i sudo su - /etc/sudoers su 该命令将启动非登录shell,即虽然以该用户身份启动shell,但使用的是原始用户的环境设置。普通用户账户运行 su 命令切换到另一用户账户,需提供要切换的账户的密码。root用户&…...
算法-同余原理
在计算n个数相加或者相乘再取余时,中间结果可能会溢出导致结果错误,这时可以使用同余原理 一、同余原理 ①加法同余 (a[1] a[2] ... a[n])% m > (a[1] % m a[2] % m ... a[n] % m) % m ② 乘法同余 (…...
深入理解卷积神经网络(CNN):从原理到实践
引言 卷积神经网络(Convolutional Neural Networks, CNN)是深度学习领域最具影响力的架构之一,尤其在计算机视觉任务中表现出色。自2012年AlexNet在ImageNet竞赛中一战成名以来,CNN不断演进,推动着图像识别、医疗影像分析、自动驾驶等领域的快…...
深度学习常见模块实现001
文章目录 1.学习目的2.常见模块使用与实现2.1 ResNet18实现2.2 SeNet模块2.3 CBAM模块 1.学习目的 深度学习在图像处理这块,很多模块已经成型,并没有很多新的东西,更多的是不同的模块堆叠,所以需要我们不断总结,动手实…...
Python实现贪吃蛇三
上篇文章Python实现贪吃蛇一,实现了一个贪吃蛇的基础版本。后面第二篇文章Python实现贪吃蛇二修改了一些不足,但最近发现还有两点需要优化: 1、生成食物的时候有概率和记分牌重合 2、游戏缺少暂停功能 先看生成食物的时候有概率和记分牌重合的…...
windows server C# IIS部署
1、添加IIS功能 windows server 2012、windows server 2016、windows server 2019 说明:自带的是.net 4.5 不需要安装.net 3.5 尽量使用 windows server 2019、2016高版本,低版本会出现需要打补丁的问题 2、打开IIS 3、打开iis应用池 .net 4.5 4、添…...
LLM小白自学笔记:1.两种指令微调
一、LoRA 简单来说,LoRA不直接调整个大模型的全部参数(那样太费资源),而是在模型的某些层(通常是注意力层)加个“旁路”——两个小的矩阵(低秩矩阵)。训练时只更新这俩小矩阵&#x…...
杰弗里·辛顿:深度学习教父
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 杰弗里辛顿:当坚持遇见突破,AI迎来新纪元 一、人物简介 杰弗…...
RHCE 第一次作业
一.定义延迟任务 1.安装邮件服务 [roothaiou ~]# yum install s-nail -y 2.配置邮件服务 [roothaiou ~]# vim /etc/mail.rc 3.测试邮件服务 [roothaiou ~]# echo 88888888 | mail -v -s Passion 13571532874163.com 4.设置定时任务 [roothaiou ~]# crontab -e 二.时间同步…...
库洛游戏一面+二面
目录 一面 1. ArrayList和LinkedList的区别,就是我在插入和删除的时候他们在时间复杂度上有什么区别 2. hashmap在java的底层是怎么实现的 3. 红黑树的实现原理 4. 红黑树的特点 5. 为什么红黑树比链表查询速度快 6. 在java中字符串的操作方式有几种 7. Stri…...
基于多模态深度学习的亚急性脊髓联合变性全流程预测与个性化管理技术方案
目录 技术方案文档1. 数据收集与预处理模块2. 多模态预测模型构建3. 术前风险评估系统4. 术中实时监测系统5. 术后并发症预测与护理6. 统计分析与验证模块7. 健康教育系统技术实现说明技术方案文档 1. 数据收集与预处理模块 功能:构建数据管道,清洗并整合多源数据 伪代码示…...
蓝桥杯日期的题型
做题思路 一般分为3个步骤,首先要定义一个结构体来存储月份的天数,第一循环日期,第二判断日期是否为闰年,第三就是题目求什么 结构体 static int[] ds{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 判断是否闰年的函数 public static void f(int m,int d){//被4整…...
【树形dp题解】dfs的巧妙应用
【树形dp题解】dfs的巧妙应用 [P2986 USACO10MAR] Great Cow Gathering G - 洛谷 题目大意: Bessie 正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会。当然,她会选择最方便的地点来举办这次集会。 每个奶牛居住在 N N …...
《AI大模型应知应会100篇》第20篇:大模型伦理准则与监管趋势
第20篇:大模型伦理准则与监管趋势 摘要 随着人工智能(AI)技术的飞速发展,尤其是大模型(如GPT、PaLM等)在自然语言处理、图像生成等领域的广泛应用,AI伦理问题和监管挑战日益凸显。本文将梳理当…...
线上教学平台(vue+springboot+ssm+mysql)含文档+PPT
线上教学平台(vuespringbootssmmysql)含文档PPT 该系统是一个在线教学平台,主要分为管理员和学员两个角色;管理员界面包含首页、交流中心、学员管理、资料类型管理、学习资料管理、交流论坛、我的收藏管理、留言板管理、考试管理…...
Being-0:具有视觉-语言模型和模块化技能的人形机器人智体
25年3月来自北大、北京智源和 BeingBeyond 的论文“Being-0: A Humanoid Robotic Agent with Vision-Language Models and Modular Skills”。 构建能够在现实世界具身任务中达到人类水平表现的自主机器人智体,是人形机器人研究的终极目标。近期,基于基…...
Fiddler 进行断点测试:调试网络请求
目录 一、什么是断点测试? 二、Fiddler 的断点功能 三、如何在 Fiddler 中设置断点? 步骤 1:启动 Fiddler 步骤 2:启用断点 步骤 3:捕获请求 步骤 4:修改请求或响应 四、案例:模拟登录失…...
决策树:ID3,C4.5,CART树总结
树模型总结 决策树部分重点关注分叉的指标,多叉还是单叉,处理离散还是连续值,剪枝方法,以及回归还是分类 一、决策树 ID3(Iterative Dichotomiser 3) 、C4.5、CART决策树 ID3:确定分类规则判别指标、寻找能够最快速降低信息熵的方…...
DDS信号发生器设计
一、基本概述 1.1 DDS简介 DDS信号发生器即直接数字频率合成(Direct Digital Frequency Synthesis,简称DDS)是一种利用数字技术生成信号的方法。它通过数字信号处理技术,将数字信号转换为模拟信号,从而生成高质量的正…...
23黑马产品经理Day01
今天过了一遍23黑马产品经理的基础视频 问题思考维度 抓住核心用户 为什么需要抓住核心用户? 主要原因:用户越来越细分,保持市场竞争力,产品开发推广更聚焦 做产品为什么要了解用户:了解用户的付费点,…...
18-21源码剖析——Mybatis整体架构设计、核心组件调用关系、源码环境搭建
学习视频资料来源:https://www.bilibili.com/video/BV1R14y1W7yS 文章目录 1. 架构设计2. 核心组件及调用关系3. 源码环境搭建3.1 测试类3.2 实体类3.3 核心配置文件3.4 映射配置文件3.5 遇到的问题 1. 架构设计 Mybatis整体架构分为4层: 接口层&#…...
东方潮流亮相广州益民艺术馆|朋克编码“艺术家潮玩”系列开幕引爆热潮
4月15日,由我的宇宙旗下公司朋克编码携“艺术家潮玩”系列亮相广州白云益民艺术馆,标志着其全国文化推广计划正式启航。本次展览围绕“潮玩艺术东方文化”展开,融合传统文化与当代潮流,以年轻化方式赋能中国文化出海。 展览现场潮…...
充电宝项目:规则引擎Drools学习
文章目录 规则引擎 Drools1 问题2 规则引擎概述2.1 规则引擎2.2 使用规则引擎的优势2.3 规则引擎应用场景2.4 Drools介绍 3 Drools入门案例3.1 创建springboot项目 引入依赖3.2 添加Drools配置类3.4 创建实体类Order3.5 orderScore.drl3.6 编写测试类 4 Drools基础语法4.1 规则…...
C++零基础实践教程 文件输入输出
模块八:文件输入输出 (数据持久化) 在之前的模块中,我们学习了如何使用程序处理数据。然而,当程序结束运行时,这些数据通常会丢失。数据持久化 (Data Persistence) 指的是将程序中的数据存储到非易失性存储介质(如硬盘…...
SpringAI+DeepSeek大模型应用开发——1 AI概述
AI领域常用词汇 LLM(LargeLanguage Model,大语言模型) 能理解和生成自然语言的巨型AI模型,通过海量文本训练。例子:GPT-4、Claude、DeepSeek、文心一言、通义干问。 G(Generative)生成式: 根据上…...