springboot实现自定义注解限流

简介: springboot实现自定义注解限流

最近搭建的博客网站,详情被人刷了,特意以此来提醒该加限流处理了

引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

自定义注解实现,默认10秒内只能请求5次,当然这个是根据自己的实际情况修改

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {
    //5次
    int count() default 5;
    //10秒
    int second() default 10;
}

aop

/**
 * 限流注解
 * Created by PeakGao on 2023/3/2.
 */
@Aspect
@Component
public class IpLimitAspect extends AccessLimitIntercept {
    @Pointcut("@annotation(com.fyg.common.annotation.RateLimit)")
    public void rateLimit() {
    }
    @Before("rateLimit()")
    public void before(JoinPoint point) throws IOException, InterruptedException {
        long beginTime = System.currentTimeMillis();
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        SysLog sysLog = new SysLog();
        RateLimit ipLimit = method.getAnnotation(RateLimit.class);
        if (ipLimit != null) {
            //注解上的描述
            sysLog.setOperation(String.valueOf(ipLimit.count()) + String.valueOf(ipLimit.second()));
        }
        //请求的参数
        Object[] args = point.getArgs();
        try {
            String params = new Gson().toJson(args);
            sysLog.setParams(params);
        } catch (Exception e) {
        }
        //请求的方法名
        String className = point.getTarget().getClass().getName();
        String methodName = signature.getName();
        sysLog.setMethod(className + "." + methodName + "()");
        //获取request
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
        HttpServletResponse response = HttpContextUtils.getHttpServletResponse();
//        try {
        this.preHandle(request, response, ipLimit.count(), ipLimit.second());
//        } catch (Exception e) {
//            logger.error("限流内部程序出错:{}", e.getMessage());
//        }
        // 执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;
        logger.info("API:{},限流注解程序执行:{} 毫秒", request.getRequestURI(), time);
    }

具体实现逻辑,采用ip限制控流

/**
 * 接口限流
 * 同一个接口10s内请求超过5次进行限流
 * Created by PeakGao on 2023/3/2.
 */
public class AccessLimitIntercept extends BaseController {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, int count, int second) throws InterruptedException, IOException {
        //文章搜索则不进行限流,如需部分接口地址限流可自定义注解实现
        // 拼接redis key = IP + Api限流
        String prefix = Constant.REDIS_KEY_PREFIX + Constant.RATE_LIMIT;
        String key =  ipUtils.getIpAddr(request) + request.getRequestURI();
        // 获取redis的value
        Integer maxTimes = null;
        Object value = redisUtil.get(prefix+key);
        if (value != null) {
            maxTimes = (Integer) value;
        }
        if (maxTimes == null) {
            // 如果redis中没有该ip对应的时间则表示第一次调用,保存key到redis
            redisUtil.set(Constant.REDIS_KEY_PREFIX + Constant.RATE_LIMIT, key, 1, second);
        } else if (maxTimes < count) {
            // 如果redis中的时间比注解上的时间小则表示可以允许访问,这是修改redis的value时间
            redisUtil.set(Constant.REDIS_KEY_PREFIX + Constant.RATE_LIMIT, key, maxTimes + 1, second);
        } else {
            // 请求过于频繁
            output(response, "{\"code\":\"8002\",\"message\":\"请求过于频繁,请稍后再试\"}");
            throw new RuntimeException("API请求限流拦截启动,当前接口:【" + key + "】请求过于频繁");
        }
        return true;
    }
    public void output(HttpServletResponse response, String msg) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            outputStream.write(msg.getBytes(StandardCharsets.UTF_8));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ObjectUtils.isNotEmpty(outputStream)) {
                outputStream.flush();
                outputStream.close();
            }
        }
    }
}
目录
相关文章
|
6月前
|
安全 NoSQL Java
SpringBoot接口安全:限流、重放攻击、签名机制分析
本文介绍如何在Spring Boot中实现API安全机制,涵盖签名验证、防重放攻击和限流三大核心。通过自定义注解与拦截器,结合Redis,构建轻量级、可扩展的安全防护方案,适用于B2B接口与系统集成。
832 3
|
6月前
|
缓存 监控 Java
SpringBoot @Scheduled 注解详解
使用`@Scheduled`注解实现方法周期性执行,支持固定间隔、延迟或Cron表达式触发,基于Spring Task,适用于日志清理、数据同步等定时任务场景。需启用`@EnableScheduling`,注意线程阻塞与分布式重复问题,推荐结合`@Async`异步处理,提升任务调度效率。
908 128
|
6月前
|
XML 安全 Java
使用 Spring 的 @Aspect 和 @Pointcut 注解简化面向方面的编程 (AOP)
面向方面编程(AOP)通过分离横切关注点,如日志、安全和事务,提升代码模块化与可维护性。Spring 提供了对 AOP 的强大支持,核心注解 `@Aspect` 和 `@Pointcut` 使得定义切面与切入点变得简洁直观。`@Aspect` 标记切面类,集中处理通用逻辑;`@Pointcut` 则通过表达式定义通知的应用位置,提高代码可读性与复用性。二者结合,使开发者能清晰划分业务逻辑与辅助功能,简化维护并提升系统灵活性。Spring AOP 借助代理机制实现运行时织入,与 Spring 容器无缝集成,支持依赖注入与声明式配置,是构建清晰、高内聚应用的理想选择。
650 0
|
6月前
|
Java 测试技术 API
将 Spring 的 @Embedded 和 @Embeddable 注解与 JPA 结合使用的指南
Spring的@Embedded和@Embeddable注解简化了JPA中复杂对象的管理,允许将对象直接嵌入实体,减少冗余表与连接操作,提升数据库设计效率。本文详解其用法、优势及适用场景。
379 126
|
5月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
586 3
|
6月前
|
Java 测试技术 数据库
使用Spring的@Retryable注解进行自动重试
在现代软件开发中,容错性和弹性至关重要。Spring框架提供的`@Retryable`注解为处理瞬时故障提供了一种声明式、可配置的重试机制,使开发者能够以简洁的方式增强应用的自我恢复能力。本文深入解析了`@Retryable`的使用方法及其参数配置,并结合`@Recover`实现失败回退策略,帮助构建更健壮、可靠的应用程序。
726 1
使用Spring的@Retryable注解进行自动重试
|
6月前
|
XML Java 数据格式
常用SpringBoot注解汇总与用法说明
这些注解的使用和组合是Spring Boot快速开发和微服务实现的基础,通过它们,可以有效地指导Spring容器进行类发现、自动装配、配置、代理和管理等核心功能。开发者应当根据项目实际需求,运用这些注解来优化代码结构和服务逻辑。
433 12
|
6月前
|
传感器 Java 数据库
探索Spring Boot的@Conditional注解的上下文配置
Spring Boot 的 `@Conditional` 注解可根据不同条件动态控制 Bean 的加载,提升应用的灵活性与可配置性。本文深入解析其用法与优势,并结合实例展示如何通过自定义条件类实现环境适配的智能配置。
322 0
探索Spring Boot的@Conditional注解的上下文配置
|
6月前
|
智能设计 Java 测试技术
Spring中最大化@Lazy注解,实现资源高效利用
本文深入探讨了 Spring 框架中的 `@Lazy` 注解,介绍了其在资源管理和性能优化中的作用。通过延迟初始化 Bean,`@Lazy` 可显著提升应用启动速度,合理利用系统资源,并增强对 Bean 生命周期的控制。文章还分析了 `@Lazy` 的工作机制、使用场景、最佳实践以及常见陷阱与解决方案,帮助开发者更高效地构建可扩展、高性能的 Spring 应用程序。
250 0
Spring中最大化@Lazy注解,实现资源高效利用