How to Prevent Duplicate Submissions and Rate‑Limit APIs with the Guardian Spring Boot Starter
This article explains how the open‑source Guardian starter provides a lightweight Spring Boot solution for anti‑repeat submission and API rate limiting, covering dependency setup, annotation and YAML configuration, key generation strategies, response handling, concurrency safety, extensible architecture, monitoring endpoints, and deployment options.
Introduction
Guardian is a lightweight Spring Boot starter that provides two independent modules: anti‑repeat‑submission protection and API rate‑limiting. Both modules can be used separately and support Redis or in‑memory storage.
Anti‑Repeat Submission
Quick Start
Add the Maven dependency (use escaped tags to avoid HTML parsing):
<dependency>
<groupId>io.github.biggg-guardian</groupId>
<artifactId>guardian-repeat-submit-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>Annotate the controller method:
@PostMapping("/submit")
@RepeatSubmit(interval = 10, message = "Order is being processed, please do not submit again")
public Result submitOrder(@RequestBody OrderDTO order) {
return orderService.submit(order);
}Run the application – the protection is active. Requests from the same user, same URL and identical body within the configured interval are blocked.
Key Generation & Fallback
The framework builds a lock key from userId + url + requestBody. The request body is cached by RepeatableRequestFilter, serialized to JSON and Base64‑encoded. If userId is unavailable, the key falls back to sessionId and then to client IP, guaranteeing a non‑null key.
Whitelist
Endpoints listed under exclude-urls (Ant‑style patterns) are always allowed and bypass all anti‑repeat logic.
YAML Bulk Configuration
For many endpoints the same rule can be defined in application.yml:
guardian:
repeat-submit:
storage: redis
key-encrypt: md5
urls:
- pattern: /api/order/**
interval: 10
key-scope: user
message: "Order is being processed, please do not submit again"
- pattern: /api/sms/send
interval: 60
key-scope: ip
exclude-urls:
- /api/public/**
- /api/healthYAML rules have higher priority than annotations, and the whitelist always wins.
Response Modes
Configure guardian.repeat-submit.response-mode: exception (default) – throws RepeatSubmitException for a global exception handler. json – writes a JSON response directly, e.g. {"code":500,"msg":"...","timestamp":...}.
Custom handlers can be supplied by defining a RepeatSubmitResponseHandler bean.
API Rate Limiting
Motivation
Duplicate‑submission protection stops identical requests in a short window, but cannot limit high‑frequency calls with varying parameters. Rate limiting caps request frequency.
Quick Start
Add the Maven dependency (escaped tags):
<dependency>
<groupId>io.github.biggg-guardian</groupId>
<artifactId>guardian-rate-limit-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>Use the annotation on a controller method:
@RateLimit(qps = 10) // sliding‑window, 10 QPS
@RateLimit(qps = 5, capacity = 20, algorithm = RateLimitAlgorithm.TOKEN_BUCKET) // token bucketYAML Bulk Configuration
guardian:
rate-limit:
urls:
- pattern: /api/sms/send
qps: 1
rate-limit-scope: ip
- pattern: /api/seckill/**
qps: 10
capacity: 50
algorithm: token_bucket
rate-limit-scope: global
exclude-urls:
- /api/public/**Supported Algorithms
Sliding Window – counts requests in a fixed time window; strict enforcement (no bursts).
Token Bucket – tokens are added at a steady rate; allows bursts up to the bucket capacity. Example:
@RateLimit(qps = 5, capacity = 20, algorithm = RateLimitAlgorithm.TOKEN_BUCKET)permits up to 20 instantaneous requests, then refills at 5 per second.
Dimension Control
Rate limiting can be scoped via rate-limit-scope to: GLOBAL – a single counter shared by all users. IP – a counter per client IP. USER – a counter per authenticated user.
Response Handling
Two response modes are available ( exception or json) and a custom RateLimitResponseHandler bean can override the default behavior.
Design Details
Concurrency Safety
Redis implementations use Lua scripts for atomic operations. Local in‑memory storage synchronizes on a per‑key basis using synchronized. Both modules also provide a local storage option backed by ConcurrentHashMap with a daemon thread that cleans expired keys every five minutes.
Pluggable Architecture
All core components are defined as interfaces and instantiated with @ConditionalOnMissingBean, allowing users to replace defaults by providing their own beans. Key components include:
Key generators: RepeatSubmitKeyGenerator / RateLimitKeyGenerator Key encryptors: AbstractKeyEncrypt Storage abstractions: RepeatSubmitStorage / RateLimitStorage Response handlers: RepeatSubmitResponseHandler / RateLimitResponseHandler Shared user context:
UserContextObservability
Both modules expose Actuator endpoints for monitoring:
GET /actuator/guardian-repeat-submit // anti‑repeat statistics
GET /actuator/guardian-rate-limit // rate‑limit statisticsLogging can be enabled with log-enabled: true to record each interception decision.
Project Structure
guardian-parent
├── guardian-core # shared utilities
├── guardian-repeat-submit
│ ├── guardian-repeat-submit-core
│ └── guardian-repeat-submit-spring-boot-starter
├── guardian-rate-limit
│ ├── guardian-rate-limit-core
│ └── guardian-rate-limit-spring-boot-starter
├── guardian-storage-redis # Redis implementation shared by both modules
└── guardian-example # demo applicationModules are independent; include only the starter you need.
Conclusion
Guardian provides two plug‑in‑ready Spring Boot starters:
Anti‑repeat submission – blocks rapid duplicate requests, supports annotation/YAML configuration, multiple key scopes (user, IP, global), automatic lock release on exceptions, and context‑path‑aware matching.
API rate limiting – caps request frequency with sliding‑window or token‑bucket algorithms, supports burst handling, and offers the same three scope levels.
Both starters are lightweight alternatives to heavyweight gateways, work with Redis or local in‑memory storage, and include built‑in monitoring via Actuator.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architect's Guide
Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
