SoFunction
Updated on 2025-03-03

Implement API current limit based on AOP and Semaphore in SpringBoot

To implement rate limiting using AOP in Spring Boot:

  • Define custom annotations to mark the method that should be speed-limited.
  • Create an aspect class to intercept method calls that are annotated with custom comments.
  • Use the rate limiter component to track and perform rate limiting.
  • Processing cases where the rate limit exceeds, such as throwing a custom exception.

Rate Limiting in Spring Boot API

Rate limiting can be implemented in the Spring Boot API using a variety of techniques. A common approach is to use Spring AOP to intercept incoming requests and enforce rate limiting.

Step 1 - Define the Rate Limit Configuration

Create a configuration class where you define rate limiting parameters, such as the number of requests allowed and time periods.

@Configuration
public class RateLimitConfig {
    @Value("${}")
    private int requests;

    @Value("${}")
    private int seconds;

    // Getters and setters
}

Step 2 - Create Rate Limiting

Use Spring AOP to implement an aspect to intercept method calls and enforce rate limiting.

@Aspect
@Component
public class RateLimitAspect {
    @Autowired
    private RateLimitConfig rateLimitConfig;

    @Autowired
    private RateLimiter rateLimiter;

    @Around("@annotation(RateLimited)")
    public Object enforceRateLimit(ProceedingJoinPoint joinPoint) throws Throwable {
        String key = getKey(joinPoint);
        if (!(key, (), ())) {
            throw new RateLimitExceededException("Rate limit exceeded");
        }
        return ();
    }

    private String getKey(ProceedingJoinPoint joinPoint) {
        // Generate a unique key for the method being called        //Method signature, user ID, IP address, etc.
    }
}

Step 3 — Define RateLimited Comments

Create custom comments to mark methods that should be rate-limited.

@Target()
@Retention()
  public @interface RateLimited {
}

Step 4 - Implementing the Rate Limiter

Create a rate limiter component to manage rate limiting using the token bucket algorithm or any other suitable algorithm.

@Component
public class RateLimiter {
    private final Map<String,RateLimitedSemaphore> semaphores = new ConcurrentHashMap<>();

    public boolean tryAcquire(String key, int requests, int seconds) {
        
        long currentTime = ();

        // Calculate the time window        long startTime = currentTime - seconds * 1000;

        // Expired deletion        cleanupExpiredEntries(startTime);

        // Get semaphore        RateLimitedSemaphore semaphore = (key, k -> {
            RateLimitedSemaphore newSemaphore = new RateLimitedSemaphore(requests);
            (currentTime); // Set last acquire time
            return newSemaphore;
        });

        // Verify semaphore        boolean acquired = ();
        if (acquired) {
            (currentTime); 
            // renew        }
        return acquired;
    }

    private void cleanupExpiredEntries(long startTime) {
        Iterator<<String, RateLimitedSemaphore>> iterator = ().iterator();
        while (()) {
            <String, RateLimitedSemaphore> entry = ();
            String key = ();
            RateLimitedSemaphore semaphore = ();
            if (() < startTime) {
                ();
            }
        }
    }

    private class RateLimitedSemaphore extends Semaphore {
        private volatile long lastAcquireTime;

        public RateLimitedSemaphore(int permits) {
            super(permits);
        }

        public long getLastAcquireTime() {
            return lastAcquireTime;
        }

        public void setLastAcquireTime(long lastAcquireTime) {
             = lastAcquireTime;
        }
    }
}

Step 5 - Comment Controller Method

Annotate the controller method that should be rate-limited with annotations @RateLimited.

@RestController
public class MyController {
    @RateLimited
    @GetMapping("/api/resource")
    public ResponseEntity<String> getResource() {
        // Implementation
    }
}

Step 6 - Configure the Rate Limiting Properties

Configure the rate limiting attribute in your or .

=10
=60

To limit requests by IP address, you can extract the IP address from the incoming request and use it as a rate-limited key:

private String getKey(HttpServletRequest request) {
    String ipAddress = ();
    return ipAddress; // Use ID to make key}

You also need to modify the method RateLimit in enforceRateLimitAspect to pass the object HttpServletRequest to the getKey method:

@Around("@annotation(RateLimited)")
public Object enforceRateLimit(ProceedingJoinPoint joinPoint) throws Throwable {
   
    ServletRequestAttributes requestAttributes = (ServletRequestAttributes) ();
    HttpServletRequest request = ();

    String key = getKey(request);
    if (!(key, (), ())) {
        throw new RateLimitExceededException("Rate limit exceeded");
    }
    return ();
}

The above is the detailed content of implementing API current limit based on AOP and Semaphore in SpringBoot. For more information on implementing API current limit in SpringBoot, please pay attention to my other related articles!