当前位置:实例文章 » JAVA Web实例» [文章]Spring WebFlux 实现同一个方法在短时间内只执行一次

Spring WebFlux 实现同一个方法在短时间内只执行一次

发布人:shili8 发布时间:2024-12-27 10:27 阅读次数:0

**Spring WebFlux 实现同一个方法在短时间内只执行一次**

在 Spring WebFlux 中,我们经常需要实现一些特定的功能,例如:同一个方法在短时间内只执行一次。这种需求可能出现在多个场景中,比如:防止重复提交表单、限制 API 的请求频率等。在本文中,我们将介绍如何使用 Spring WebFlux 实现这个功能。

**1. 使用 Redis**

首先,我们可以使用 Redis 来实现这个功能。Redis 是一个内存数据库,支持分布式锁的实现。我们可以在方法执行前检查 Redis 中是否存在某个键,如果存在,则表示该方法已经被执行过一次,可以直接返回;如果不存在,则设置该键并执行方法。

javaimport org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

@Componentpublic class RedisLock {

 @Autowired private RedisTemplate redisTemplate;

 public boolean tryAcquireLock(String key) {
 // 尝试获取锁,等待10 秒,如果超过10 秒仍然无法获取,则放弃 if (redisTemplate.opsForValue().setIfAbsent(key, "1") != null) {
 return true;
 }
 // 如果超过10 秒仍然无法获取,则放弃 try {
 Thread.sleep(10000);
 } catch (InterruptedException e) {
 Thread.currentThread().interrupt();
 }
 return redisTemplate.opsForValue().setIfAbsent(key, "1") != null;
 }

 public void releaseLock(String key) {
 //释放锁 redisTemplate.delete(key);
 }
}


javaimport org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestControllerpublic class TestController {

 @Autowired private RedisLock redisLock;

 @GetMapping("/test")
 public String test() {
 // 尝试获取锁 if (redisLock.tryAcquireLock("lock_key")) {
 try {
 // 执行方法 Thread.sleep(1000);
 return "执行成功";
 } catch (InterruptedException e) {
 Thread.currentThread().interrupt();
 } finally {
 //释放锁 redisLock.releaseLock("lock_key");
 }
 } else {
 return "获取锁失败";
 }
 }
}


**2. 使用 ZooKeeper**

ZooKeeper 是一个分布式协调服务,支持实现分布式锁。我们可以在方法执行前检查 ZooKeeper 中是否存在某个节点,如果存在,则表示该方法已经被执行过一次,可以直接返回;如果不存在,则创建该节点并执行方法。

javaimport org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;

public class ZookeeperLock {

 private static final String ZOOKEEPER_PATH = "/lock_key";

 public boolean tryAcquireLock(ZooKeeper zooKeeper) {
 // 尝试获取锁,等待10 秒,如果超过10 秒仍然无法获取,则放弃 try {
 byte[] data = zooKeeper.getData(ZOOKEEPER_PATH, false, null);
 if (data != null) {
 return true;
 }
 zooKeeper.create(ZOOKEEPER_PATH, "1".getBytes(), CreateMode.EPHEMERAL, null);
 return true;
 } catch (KeeperException e) {
 // 如果超过10 秒仍然无法获取,则放弃 try {
 Thread.sleep(10000);
 } catch (InterruptedException e1) {
 Thread.currentThread().interrupt();
 }
 return zooKeeper.getData(ZOOKEEPER_PATH, false, null) != null;
 }
 }

 public void releaseLock(ZooKeeper zooKeeper) {
 //释放锁 try {
 zooKeeper.delete(ZOOKEEPER_PATH, -1);
 } catch (InterruptedException e) {
 Thread.currentThread().interrupt();
 } catch (KeeperException e) {
 // ignore }
 }
}


javaimport org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestControllerpublic class TestController {

 @Autowired private ZookeeperLock zookeeperLock;

 @GetMapping("/test")
 public String test() {
 // 尝试获取锁 if (zookeeperLock.tryAcquireLock(new ZooKeeper("127.0.0.1:2181",10000, null))) {
 try {
 // 执行方法 Thread.sleep(1000);
 return "执行成功";
 } catch (InterruptedException e) {
 Thread.currentThread().interrupt();
 } finally {
 //释放锁 zookeeperLock.releaseLock(new ZooKeeper("127.0.0.1:2181",10000, null));
 }
 } else {
 return "获取锁失败";
 }
 }
}


**3. 使用自定义的分布式锁**

我们可以使用 Java 的 `synchronized` 关键字或 `Lock` 接口来实现分布式锁。这种方式相比于使用 Redis 或 ZooKeeper 来说,更加简单,但也可能导致性能问题。

javaimport java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class CustomLock {

 private final Lock lock = new ReentrantLock();

 public boolean tryAcquireLock() {
 // 尝试获取锁,等待10 秒,如果超过10 秒仍然无法获取,则放弃 if (lock.tryLock()) {
 return true;
 }
 try {
 Thread.sleep(10000);
 } catch (InterruptedException e) {
 Thread.currentThread().interrupt();
 }
 return lock.tryLock();
 }

 public void releaseLock() {
 //释放锁 lock.unlock();
 }
}


javaimport org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestControllerpublic class TestController {

 @Autowired private CustomLock customLock;

 @GetMapping("/test")
 public String test() {
 // 尝试获取锁 if (customLock.tryAcquireLock()) {
 try {
 // 执行方法 Thread.sleep(1000);
 return "执行成功";
 } catch (InterruptedException e) {
 Thread.currentThread().interrupt();
 } finally {
 //释放锁 customLock.releaseLock();
 }
 } else {
 return "获取锁失败";
 }
 }
}


综上所述,我们可以使用 Redis、ZooKeeper 或自定义的分布式锁来实现同一个方法在短时间内只执行一次。每种方式都有其优缺点,选择哪种方式取决于具体需求和场景。

其他信息

其他资源

Top