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 RedisTemplateredisTemplate; 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 或自定义的分布式锁来实现同一个方法在短时间内只执行一次。每种方式都有其优缺点,选择哪种方式取决于具体需求和场景。