Loading... # Java 使用 Redisson + 注解 + AOP 实现防重复请求指南 🚀 在高并发场景下,防止 **重复请求** 对于保障系统数据的一致性和完整性至关重要。本文将介绍如何结合 **Redisson**、**自定义注解** 和 **AOP(面向切面编程)**,在 Java 项目中实现防重复请求的功能。 --- ## 一、项目依赖配置 📦 首先,在 `pom.xml` 中添加 Redisson 依赖: ```xml <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.16.2</version> </dependency> ``` **解释**:引入 Redisson 库,以便使用 Redis 分布式锁实现防重复提交。 --- ## 二、自定义防重复请求注解 🏷️ 创建一个自定义注解 `@AvoidRepeatableCommit`: ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AvoidRepeatableCommit { /** * 锁定时间,单位:秒 */ int lockTime() default 5; } ``` **解释**: - `@Target(ElementType.METHOD)`:注解作用于方法上。 - `@Retention(RetentionPolicy.RUNTIME)`:注解在运行时可获取。 - `int lockTime() default 5;`:设置锁定时间,默认 5 秒。 --- ## 三、AOP 切面实现逻辑 🔍 创建切面类,拦截带有 `@AvoidRepeatableCommit` 注解的方法。 ```java @Aspect @Component public class AvoidRepeatableCommitAspect { @Autowired private RedissonClient redissonClient; @Pointcut("@annotation(com.example.AvoidRepeatableCommit)") public void avoidRepeatableCommitPointcut() {} @Around("avoidRepeatableCommitPointcut()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); AvoidRepeatableCommit annotation = method.getAnnotation(AvoidRepeatableCommit.class); int lockTime = annotation.lockTime(); String key = generateKey(joinPoint); RLock lock = redissonClient.getLock(key); boolean isLocked = lock.tryLock(0, lockTime, TimeUnit.SECONDS); if (!isLocked) { throw new RuntimeException("请勿重复提交请求"); } try { return joinPoint.proceed(); } finally { lock.unlock(); } } } ``` **解释**: - `@Aspect`:标记该类为切面。 - `@Pointcut`:定义切入点,匹配带有 `@AvoidRepeatableCommit` 注解的方法。 - `@Around`:环绕通知,执行方法前后进行逻辑处理。 - `generateKey(joinPoint)`:生成唯一键,用于锁的区分。 - `lock.tryLock(0, lockTime, TimeUnit.SECONDS)`:尝试获取锁,立即返回,设置锁超时时间。 - `lock.unlock()`:方法执行完毕后释放锁。 --- ## 四、生成唯一键的方法 🔑 实现 `generateKey` 方法,确保对同一请求生成相同的键。 ```java private String generateKey(ProceedingJoinPoint joinPoint) { StringBuilder sb = new StringBuilder(); sb.append(joinPoint.getTarget().getClass().getName()); sb.append(".").append(joinPoint.getSignature().getName()); Object[] args = joinPoint.getArgs(); for (Object arg : args) { sb.append(".").append(arg.toString()); } return sb.toString(); } ``` **解释**: - 拼接 **类名**、**方法名** 和 **参数列表**,确保键的唯一性。 - 这样可针对不同请求参数,区分不同的锁。 --- ## 五、配置 Redisson 客户端 🔧 在配置类中,创建 RedissonClient Bean。 ```java @Configuration public class RedissonConfig { @Bean public RedissonClient redissonClient() { Config config = new Config(); config.useSingleServer() .setAddress("redis://localhost:6379") .setPassword("yourpassword"); return Redisson.create(config); } } ``` **解释**: - `useSingleServer()`:使用单节点 Redis 服务器。 - `setAddress`:设置 Redis 服务器地址。 - `setPassword`:设置 Redis 密码(如果有)。 --- ## 六、应用注解到业务方法 ✨ 在需要防重复提交的方法上,添加 `@AvoidRepeatableCommit` 注解。 ```java @RestController public class OrderController { @AvoidRepeatableCommit(lockTime = 10) @PostMapping("/createOrder") public String createOrder(@RequestBody Order order) { // 业务逻辑 return "订单创建成功"; } } ``` **解释**: - `@AvoidRepeatableCommit(lockTime = 10)`:设置锁定时间为 10 秒。 - 当用户在 10 秒内重复提交相同请求,将会被拦截。 --- ## 七、工作流程图 🗺️ ```mermaid flowchart TD A[请求进入] --> B[AOP切面拦截] B --> C{尝试获取Redis锁} C -- 获取成功 --> D[执行目标方法] C -- 获取失败 --> E[抛出异常: 请勿重复提交请求] D --> F[释放锁] D --> G[返回结果] E --> G ``` **解释**:流程图展示了防重复请求的处理流程,从请求进入到结果返回。 --- ## 八、注意事项 ⚠️ - **<font color="red">锁的粒度</font>**:生成唯一键时,要考虑锁的粒度,避免误锁其他请求。 - **<font color="red">锁的超时时间</font>**:设置合理的锁超时时间,防止长时间占用资源。 - **<font color="red">异常处理</font>**:在捕获异常时,要确保锁能够被释放,避免死锁。 --- ## 九、总结 🎯 通过结合 **Redisson**、**注解** 和 **AOP**,我们实现了一个简洁高效的防重复请求方案。这种方式解耦了业务逻辑和防重复提交的功能,提升了代码的可维护性和扩展性。 希望本文对您有所帮助,祝您编码愉快!🚀 --- 最后修改:2024 年 11 月 28 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏