第一步:
引入切面的mavne坐标
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
第二步:
新建限流注解:
package com.seckillpro.seckill_pro.config;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import java.lang.annotation.*;
/**
* @Author zdj
* @Date 2022/11/11 9:40
* @Version 1.0
*/
@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestRateLimiter {
String limiterName() default "";
RateType mode() default RateType.PER_CLIENT;
long rate() default 10;
long rateInterval() default 1;
RateIntervalUnit rateIntervalUnit() default RateIntervalUnit.SECONDS;
}
第三步:
创建切面类进行限流
package com.seckillpro.seckill_pro.config;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RRateLimiter;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
/**
* @author zdj
* @version 1.0.0
* @description MyRedisLimiter注解的切面类
*/
@Aspect
@Component
public class RedisLimiterAspect {
private final Logger logger = LoggerFactory.getLogger(RedisLimiterAspect.class);
/**
* 当前响应
*/
@Autowired
private HttpServletResponse response;
/**
* 当前请求
*/
@Autowired
private HttpServletRequest request;
/**
* redis服务
*/
@Autowired
private RedissonClient redissonClient;
/**
* 对有限流注解的方法进行拦截
*/
@Pointcut("@annotation(com.seckillpro.seckill_pro.config.RequestRateLimiter)")
public void pointcut(){
}
/**
* 对切点进行继续处理
*/
@Around("pointcut()")
public Object process(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
//使用反射获取RequestRateLimiter注解
MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
//没有添加限流注解的方法直接放行
RequestRateLimiter rateLimiter = signature.getMethod().getDeclaredAnnotation(RequestRateLimiter.class);
if(ObjectUtils.isEmpty(rateLimiter)){
return proceedingJoinPoint.proceed();
}
String limiterName = rateLimiter.limiterName();
long rate = rateLimiter.rate();
long rateInterval = rateLimiter.rateInterval();
RateIntervalUnit rateIntervalUnit = rateLimiter.rateIntervalUnit();
RateType mode = rateLimiter.mode();
RRateLimiter rRateLimiter = redissonClient.getRateLimiter(limiterName);
rRateLimiter.setRate(mode, rate, rateInterval, rateIntervalUnit);
if (rRateLimiter.tryAcquire()) {
return proceedingJoinPoint.proceed();
// 限流了则返回
} else {
this.limitStreamBackMsg();
return null;
}
}
/**
* 被拦截的人,提示消息
*/
private void limitStreamBackMsg() {
response.setHeader("Content-Type", "application/json;charset=UTF8");
PrintWriter writer = null;
try {
writer = response.getWriter();
writer.println("{\"code\":500826,\"message\":\"活动太火爆了,请稍后再试\",\"obj\":\"null\"}");
writer.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (writer != null) {
writer.close();
}
}
}
}
第四步:
在controlle中使用
/**
* 限流测试
* @return
*/
@RequestMapping(value = "/limitTest", method = RequestMethod.GET)
@ApiOperation(value = "限流测试")
@RequestRateLimiter(limiterName = "limitTest", rate = 10) // 代表每秒只能10条请求
public RespBean limitTest() {
return RespBean.success("成功");
}
测试: