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.

Java Architect Handbook
Java Architect Handbook
Java Architect Handbook
Prevent Duplicate Submissions and Rate‑Limit APIs with the Guardian Spring Boot Starter

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/health

Response 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 QPS

Or 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: exception

Algorithms

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 stats

Statistics 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 application

Conclusion

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.

JavaRedisSpring BootYAMLStarterguardianrate-limitanti-duplicate
Java Architect Handbook
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.