GateKeeper is a lightweight, low-latency, thread-safe rate-limiting middleware system built on Java 17 and Spring Boot 3. It utilizes an in-memory Fixed Window counter pattern with non-blocking atomic operations to protect backend services from abusive request volumes, DoS attempts, and accidental bursts.
Comprehensive project architecture and requirement specifications are maintained in the docs/ directory:
- Product Requirements Document (PRD)
- Software Requirements Specification (SRS)
- System Architecture & Design
- Use Cases & Scenarios
- API Contract & Interception Documentation
- Java Development Kit (JDK): Version 17 or higher
- Apache Maven: Version 3.8+ (or use the included
./mvnwwrapper) - cURL or Postman: For sending test HTTP traffic and verifying rate-limiting headers
gatekeeper
├── pom.xml
├── docs/
│ ├── PRD.md
│ ├── SRS.md
│ ├── Architecture.md
│ ├── UseCases.md
│ └── API_Contract.md
└── src/main/java/com/omar/gatekeeper/
├── GatekeeperApplication.java # Application entry point
├── config/
│ └── WebConfig.java # WebMvcConfigurer registering interceptors
├── controller/
│ └── TestController.java # Health check endpoint (/api/test)
├── interceptor/
│ └── RateLimitInterceptor.java # Pre-controller request interceptor
└── service/
└── RateLimitingService.java # Lockless Fixed Window rate-limiting service
Rate-limiting limits and window configurations are externalized in src/main/resources/application.properties:
spring.application.name=gatekeeper
# The maximum number of requests allowed per client IP within a single window
rate-limit.max-requests=10
# The duration of each window in milliseconds (e.g., 60000 = 1 minute)
rate-limit.window-size-ms=60000| Property Key | Type | Default | Description |
|---|---|---|---|
rate-limit.max-requests |
Integer | 10 |
The maximum number of requests permitted per unique client IP within the configured window. |
rate-limit.window-size-ms |
Long | 60000 |
The duration of the fixed time window in milliseconds (60,000 ms = 1 minute). |
./mvnw clean package -DskipTests./mvnw spring-boot:runBy default, the server will start on port 8080.
Send a single request to verify the server is active:
curl -i http://localhost:8080/api/testExpected Response:
HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
GateKeeper Server is up and running!Send 15 requests sequentially to trigger the rate limiter (configured threshold is 10):
for i in {1..15}; do
echo -n "Request $i: ";
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8080/api/test;
doneExpected Output:
Request 1: 200
...
Request 10: 200
Request 11: 429
...
Request 15: 429
Simulate traffic passing through a reverse proxy:
curl -i -H "X-Forwarded-For: 203.0.113.55" http://localhost:8080/api/test- State is stored in a
ConcurrentHashMap<String, Window>. Windowis defined as an immutable Java record:private record Window(long startTime, int count) {}
- Increments and resets are managed atomically through
ConcurrentHashMap.compute():This design ensures lock-free atomicity per IP key without coarse synchronized blocks or thread starvation.Window currentWindow = requestMap.compute(ip, (key, existingWindow) -> { if (existingWindow == null || (now - existingWindow.startTime()) > windowSizeMs) { return new Window(now, 1); } return new Window(existingWindow.startTime(), existingWindow.count() + 1); });