SpringBoot如何使用AOP+Redis实现接口限流实现全过程(值得珍藏)

点击下载《SpringBoot如何使用AOP+Redis实现接口限流实现全过程(值得珍藏)》

1. 引言

在当今的微服务架构中,接口限流是一个常见的需求,用以防止系统过载和潜在的资源耗尽。Spring Boot 提供了一种方便的方式来实施接口限流,结合 AOP(面向切面编程)和 Redis 存储限流信息,可以有效地实现这一目标。

2. 实现原理

  1. AOP:
    Spring Boot的AOP(Aspect Oriented Programming)是一种面向切面编程的框架,通过预编译方式和运行期动态代理,在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP的主要目标是解决一些系统层面上的问题,如日志、事务、权限等。

    在Spring Boot中,AOP通过定义横跨多个对象和函数的通用行为,提供了一种方便的机制来解耦代码中的不同关注点。AOP的编程思想是把对类对象的横切问题点,从业务逻辑中分离出来,从而达到解耦的目的,增加代码的复用性,提高开发效率。

    Spring Boot的AOP基于切面(Aspect)和切点(Pointcut)两个概念。切面定义了需要在方法调用前、调用后、抛出异常时、返回时等关键节点执行的通用行为,而切点定义了需要拦截的方法集合。Spring Boot的AOP通过在应用程序运行时动态地将切面织入到切点定义的方法集合中,从而实现了对方法的拦截和增强。

    Spring Boot的AOP支持基于注解和XML配置两种方式。在基于XML配置的AOP中,开发人员可以使用Spring提供的XML配置来定义切面和切点。而在基于注解的AOP中,开发人员只需要在相应的类或方法上添加相应的注解即可完成切面的定义和织入。

    Spring Boot的AOP能够应用于各种场景,如日志管理、事务管理、安全控制、性能监控等。通过使用AOP,开发人员可以更加灵活地处理这些系统层面的问题,提高系统的可维护性和可扩展性。

  2. Redis:
    Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。与Memcached类似,Redis支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)和zset(有序集合)。Redis可以弥补Memcached这类key-value存储的不足,在部分场合可以对关系数据库起到很好的补充作用,满足实时的高并发需求。

    Redis还支持在服务器端计算集合的并、交和补集(difference)等,还支持多种排序功能。此外,Redis提供了RDB与AOF等多种不同级别的持久化方式。RDB持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot)。AOF持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。Redis可以同时使用AOF持久化和RDB持久化。

    此外,Redis还具备LRU淘汰、事务实现、以及不同级别的硬盘持久化等能力,并且支持副本集和通过RedisSentinel实现的高可用方案,同时还支持通过Redis Cluster实现的数据自动分片能力。

在这里插入图片描述

3. 实现步骤

3.1 添加依赖

首先,你需要在你的 pom.xml 文件中添加 Spring Boot Starter AOP 和 Spring Boot Starter Data Redis 的依赖:

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

3.2 配置 Redis

application.propertiesapplication.yml 文件中配置 Redis 的连接信息:

# application.properties  
spring.redis.host=localhost  
spring.redis.port=6379

3.3 创建 Redis 存储类

在这里插入图片描述

创建一个类来封装与 Redis 交互的逻辑:

@Service  
public class RateLimiterService {  
    @Autowired  
    private StringRedisTemplate redisTemplate;  
    private static final String PREFIX = "rate_limiter:";  
    private static final int DEFAULT_LIMIT = 10; // 默认限流次数  
    private static final int DEFAULT_EXPIRE_TIME = 60; // 默认过期时间(秒)  
  
    public boolean isAllow(@NonNull String key) {  
        // 获取当前时间戳(毫秒)  
        long now = System.currentTimeMillis();  
        // 从 Redis 中获取限流信息(如果存在)  
        String value = redisTemplate.opsForValue().get(PREFIX + key);  
        if (value == null) { // 如果不存在,则设置默认限流信息并返回 true(允许访问)  
            redisTemplate.opsForValue().set(PREFIX + key, String.valueOf(DEFAULT_LIMIT), DEFAULT_EXPIRE_TIME, TimeUnit.SECONDS);  
            return true;  
        } else { // 如果存在,则解析限流信息并返回是否允许访问(根据实际需求修改)  
            int limit = Integer.parseInt(value); // 假设我们使用简单的计数器实现限流,这里只是简单地将计数器减一并判断是否小于零。实际应用中可能需要更复杂的策略。  
            if (limit > 0) { // 如果还有剩余访问次数,则更新 Redis 中的限流信息并返回 true(允许访问)  
                redisTemplate.opsForValue().set(PREFIX + key, String.valueOf(limit - 1), DEFAULT_EXPIRE_TIME, TimeUnit.SECONDS);  
                return true;  
            } else { // 如果已经达到限流次数,则返回 false(拒绝访问)  
                return false;  
            }  
        }  
    }  
}

3.4 创建 AOP 切面

在这里插入图片描述

创建一个 AOP 切面来拦截特定接口的访问:

@Aspect  
@Component  
public class RateLimitAspect {  
  
    @Autowired  
    private RateLimiterService rateLimiterService; // 注入 Redis 存储类,用于处理限流逻辑。  
  
    @Pointcut("execution(* com.example.demo.controller.*.*(..))") // 定义切入点表达式,拦截所有 com.example.demo.controller 包下的方法。你可以根据需要修改这个表达式来拦截特定的接口。  
    public void controllerMethods() {} // 定义一个空的方法,作为切入点表达式的方法签名。这个方法不需要实现任何逻辑。  
  
    @Around("controllerMethods()") // 使用 @Around 注解来定义环绕通知。这个通知会在目标方法执行前后执行。你可以在这里添加自定义的逻辑来处理限流。例如:记录日志、抛出异常等。这里我们只是简单地调用 rateLimiterService 的 isAllow 方法。  
    public Object rateLimit(ProceedingJoinPoint joinPoint) throws Throwable {  
        String key = // 生成唯一的 key,用于标识用户或请求。例如,可以使用用户的 ID 或 IP 地址。  
        if (rateLimiterService.isAllow(key)) {  
            return joinPoint.proceed(); // 如果允许访问,则继续执行目标方法。  
        } else {  
            // 如果达到限流阈值,可以抛出异常或返回特定的响应。  
            throw new CustomRateLimitException("Rate limit exceeded");  
        }  
    }  
}

3.5 处理限流逻辑

在环绕通知中,你可以根据 rateLimiterService.isAllow(key) 的返回值来决定是否允许用户访问:

@Around("controllerMethods()")  
public Object rateLimit(ProceedingJoinPoint joinPoint) throws Throwable {  
    String key = // 生成唯一的 key,用于标识用户或请求。例如,可以使用用户的 ID 或 IP 地址。  
    if (rateLimiterService.isAllow(key)) {  
        return joinPoint.proceed(); // 如果允许访问,则继续执行目标方法。  
    } else {  
        // 如果达到限流阈值,可以抛出异常或返回特定的响应。  
        throw new CustomRateLimitException("Rate limit exceeded");  
    }  
}

3.6 自定义异常

创建一个自定义的异常类来表示限流阈值已达:

public class CustomRateLimitException extends RuntimeException {  
    public CustomRateLimitException(String message) {  
        super(message);  
    }  
}

3.7 配置切面

最后,你需要在 Spring Boot 的配置类中启用 AOP 并配置切面:

@EnableAspectJAutoProxy  
@Configuration  
public class AppConfig {  
    @Bean  
    public RateLimitAspect rateLimitAspect() {  
        return new RateLimitAspect();  
    }  
}

4. 总结

通过结合 AOP 和 Redis,我们可以实现一个灵活且可扩展的接口限流机制。AOP 使得我们可以将限流逻辑与业务逻辑分离,使得代码更加清晰和易于维护。而 Redis 作为一个高性能的存储系统,可以快速地处理大量的限流请求。在实际应用中,你可能需要根据具体需求调整限流策略和 Redis 的使用方式。

点击下载《SpringBoot如何使用AOP+Redis实现接口限流实现全过程(值得珍藏)》

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring Boot结合Redis实现接口限的步骤如下[^1][^2]: 1. 引入依赖:在Spring Boot项目的pom.xml文件中添加RedisAOP的相关依赖。 2. 配置RedisTemplate:在Spring Boot的配置文件中配置Redis连接信息,包括主机名、端口号、密码等。 3. 创建自定义注解:使用@RateLimiter注解来标记需要进行接口限流的方法。 4. 编写切面类:创建一个切面类,使用@Aspect注解标记,并在该类中编写切点和通知方法。 5. 实现接口限流逻辑:在通知方法中,使用Redis的原子操作来实现接口限流的逻辑。可以使用Redis的incr命令来对接口的访问次数进行计数,然后根据设定的阈值来判断是否限流。 6. 配置切面:在Spring Boot的配置类中,使用@EnableAspectJAutoProxy注解开启AOP功能,并将切面类添加到容器中。 7. 在需要进行接口限流的方法上添加注解:在需要进行接口限流的方法上添加@RateLimiter注解,并配置相关参数,如限流的阈值、时间窗口大小等。 8. 测试接口限流效果:启动Spring Boot应用程序,并访问被限流接口,观察接口的访问频率是否受到限制。 以下是一个示例代码,演示了如何使用Spring Boot和Redis实现接口限流: ```java // 1. 创建自定义注解 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface RateLimiter { int value() default 10; // 默认限流阈值为10 int window() default 60; // 默认时间窗口为60秒 } // 2. 编写切面类 @Aspect @Component public class RateLimiterAspect { @Autowired private RedisTemplate<String, String> redisTemplate; @Around("@annotation(rateLimiter)") public Object around(ProceedingJoinPoint joinPoint, RateLimiter rateLimiter) throws Throwable { String methodName = joinPoint.getSignature().getName(); String key = "rate_limiter:" + methodName; int limit = rateLimiter.value(); int window = rateLimiter.window(); // 使用Redis的incr命令对接口的访问次数进行计数 Long count = redisTemplate.opsForValue().increment(key, 1); if (count == 1) { // 设置过期时间,保证计数器在一定时间后自动清零 redisTemplate.expire(key, window, TimeUnit.SECONDS); } if (count > limit) { // 超过限流阈值,抛出异常或返回错误信息 throw new RuntimeException("接口访问频率超过限制"); } // 执行原方法 return joinPoint.proceed(); } } // 3. 在需要进行接口限流的方法上添加注解 @RestController public class DemoController { @RateLimiter(value = 5, window = 60) // 每分钟最多访问5次 @GetMapping("/demo") public String demo() { return "Hello World!"; } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤蓬&听雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值