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.

Architect's Guide
Architect's Guide
Architect's Guide
How to Prevent Duplicate Submissions and Rate‑Limit APIs with the Guardian Spring Boot Starter

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

YAML 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 bucket

YAML 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:

UserContext

Observability

Both modules expose Actuator endpoints for monitoring:

GET /actuator/guardian-repeat-submit   // anti‑repeat statistics
GET /actuator/guardian-rate-limit      // rate‑limit statistics

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

Modules 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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavamavenSpring Bootrate limitingAnti repeat submitAPI protection
Architect's Guide
Written by

Architect's Guide

Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.

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.