Implementing Interface Rate Limiting in Spring Boot with Annotations and Redis

This article demonstrates how to create a custom @AccessLimit annotation, implement a Spring MVC interceptor that uses Redis to count requests, register the interceptor in a Spring Boot application, and apply the annotation to controller methods to achieve rate‑limiting functionality.

Java Captain
Java Captain
Java Captain
Implementing Interface Rate Limiting in Spring Boot with Annotations and Redis

The article explains a practical way to add rate‑limiting to Spring Boot APIs by using a custom annotation and Redis.

Technical points: basic Spring Boot knowledge, Redis basic operations

First, define an annotation class:

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
 * @author yhq
 * @date 2018/9/10 15:52
 */
@Retention(RUNTIME)
@Target(METHOD)
public @interface AccessLimit {
    int seconds();
    int maxCount();
    boolean needLogin() default true;
}

Next, implement the interceptor that checks the annotation, retrieves the request count from Redis, and decides whether to allow the request:

import com.alibaba.fastjson.JSON;
import com.example.demo.action.AccessLimit;
import com.example.demo.redis.RedisService;
import com.example.demo.result.CodeMsg;
import com.example.demo.result.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
/**
 * @author yhq
 * @date 2018/9/10 16:05
 */
@Component
public class FangshuaInterceptor extends HandlerInterceptorAdapter {
    @Autowired
    private RedisService redisService;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod hm = (HandlerMethod) handler;
            AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
            if (accessLimit == null) {
                return true;
            }
            int seconds = accessLimit.seconds();
            int maxCount = accessLimit.maxCount();
            boolean login = accessLimit.needLogin();
            String key = request.getRequestURI();
            if (login) {
                // Assume user id is 1 for demonstration; replace with actual user id retrieval
                key += "" + "1";
            }
            AccessKey ak = AccessKey.withExpire(seconds);
            Integer count = redisService.get(ak, key, Integer.class);
            if (count == null) {
                // first access
                redisService.set(ak, key, 1);
            } else if (count < maxCount) {
                // increment count
                redisService.incr(ak, key);
            } else {
                // exceed limit
                render(response, CodeMsg.ACCESS_LIMIT_REACHED);
                return false;
            }
        }
        return true;
    }
    private void render(HttpServletResponse response, CodeMsg cm) throws Exception {
        response.setContentType("application/json;charset=UTF-8");
        OutputStream out = response.getOutputStream();
        String str = JSON.toJSONString(Result.error(cm));
        out.write(str.getBytes("UTF-8"));
        out.flush();
        out.close();
    }
}

Register the interceptor in a Spring Boot configuration class:

import com.example.demo.ExceptionHander.FangshuaInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
 * @author yhq
 * @date 2018/9/10 15:58
 */
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
    @Autowired
    private FangshuaInterceptor interceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(interceptor);
    }
}

Finally, apply the @AccessLimit annotation to a controller method to protect the endpoint:

import com.example.demo.result.Result;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
 * @author yhq
 * @date 2018/9/10 15:49
 */
@Controller
public class FangshuaController {
    @AccessLimit(seconds = 5, maxCount = 5, needLogin = true)
    @RequestMapping("/fangshua")
    @ResponseBody
    public Result<String> fangshua() {
        return Result.success("请求成功");
    }
}

The complete example shows how to combine a custom annotation, Redis caching, and a Spring MVC interceptor to achieve simple, configurable rate limiting for API interfaces.

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.

JavaredisSpring BootInterceptorannotationsrate limiting
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

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.