Prevent Duplicate Submissions and Rate‑Limit APIs with the Guardian Spring Boot Starter
This article introduces Guardian, a lightweight Spring Boot starter that provides anti‑duplicate‑submission protection and request rate limiting, explains how to integrate it via Maven, configure it with annotations or YAML, and details its internal workflow, storage options, concurrency handling, and monitoring capabilities.
Overview
Guardian is a lightweight Spring Boot starter (v1.3.0) that offers two independent features: anti‑duplicate submission protection and API rate limiting. Both can be added to a project via a single dependency and work without heavy gateway solutions.
Getting Started
Add the required starter to pom.xml:
<dependency>
<groupId>io.github.biggg-guardian</groupId>
<artifactId>guardian-repeat-submit-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>or for rate limiting:
<dependency>
<groupId>io.github.biggg-guardian</groupId>
<artifactId>guardian-rate-limit-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>Source code is available at https://github.com/BigGG-Guardian/guardian.
1. Anti‑Duplicate Submission
Three‑step setup
Import the starter dependency.
Add the @RepeatSubmit annotation to the controller method:
@PostMapping("/submit")
@RepeatSubmit(interval = 10, message = "Order is being processed, please do not resubmit")
public Result submitOrder(@RequestBody OrderDTO order) {
return orderService.submit(order);
}Run the application – the interceptor is active.
Why not a raw Redis lock?
Key generation must consider request parameters, user identity, and context path. Guardian automatically caches the request body, serializes parameters to JSON, encodes them, and builds a robust key.
It also handles cases where the user is not logged in (fallback to session ID or client IP) and releases the lock automatically if the request throws an exception.
Whitelist and Configuration
Configure URLs to exclude from protection using exclude-urls (Ant‑style patterns). YAML configuration overrides annotations:
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 resubmit"
- pattern: /api/sms/send
interval: 60
key-scope: ip
exclude-urls:
- /api/public/**
- /api/healthResponse Modes
Two response strategies are supported:
exception (default) – throws RepeatSubmitException which can be handled globally.
json – returns a JSON payload directly, e.g. {"code":500,"msg":"...","timestamp":...}.
Custom response handlers can be registered by providing a RepeatSubmitResponseHandler bean.
Storage Options
By default Guardian uses Redis. For environments without Redis, set storage: local to use an in‑memory ConcurrentHashMap with periodic cleanup.
2. API Rate Limiting
Motivation
Duplicate‑submission protection cannot stop high‑frequency attacks where each request carries different parameters. Rate limiting caps the request rate per endpoint.
Three‑step setup
Add the rate‑limit starter dependency.
Annotate the method with @RateLimit:
@RateLimit(qps = 10) // sliding window, max 10 QPSOr token‑bucket mode:
@RateLimit(qps = 5, capacity = 20, algorithm = RateLimitAlgorithm.TOKEN_BUCKET)Or configure multiple endpoints via YAML (annotation takes lower priority):
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/**
response-mode: exceptionAlgorithms
Sliding window strictly limits the number of requests within a fixed time window (e.g., 10 QPS). Token bucket allows bursts up to the bucket capacity while refilling tokens at a steady rate.
Rate‑limit Dimensions
Guardian supports three scopes: GLOBAL – a single counter for the endpoint. IP – separate counters per client IP (ideal for SMS or captcha). USER – separate counters per authenticated user.
Response Modes
Same as anti‑duplicate: exception (default) or json. Custom RateLimitResponseHandler beans can override the default behavior.
3. Design Details
Concurrency Safety
When using Redis, both sliding‑window and token‑bucket algorithms run inside Lua scripts, guaranteeing atomicity. Local storage relies on synchronized blocks keyed by the generated lock key.
Memory Management for Local Cache
Local ConcurrentHashMap entries are cleaned every 5 minutes by a daemon thread to prevent unbounded growth.
Pluggable Architecture
All core components are defined as interfaces and instantiated with @ConditionalOnMissingBean. Users can replace any component (key generator, storage, response handler, etc.) by providing their own bean.
Observability
Both modules expose Actuator endpoints:
GET /actuator/guardian-repeat-submit // anti‑duplicate stats
GET /actuator/guardian-rate-limit // rate‑limit statsStatistics include total request count, pass count, block count, block rate, and top blocked APIs.
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 // sample applicationConclusion
Guardian provides two independent, lightweight starters for Spring Boot projects: one to block duplicate submissions within a configurable interval, and another to limit request rates using sliding‑window or token‑bucket algorithms. Both support annotation‑based and YAML‑based configuration, flexible key scopes, automatic lock release, whitelist handling, pluggable components, and built‑in monitoring via Actuator.
Java Architect Handbook
Focused on Java interview questions and practical article sharing, covering algorithms, databases, Spring Boot, microservices, high concurrency, JVM, Docker containers, and ELK-related knowledge. Looking forward to progressing together with you.
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.
