nginx和gateway网关都是对整个系统进行访问限流
通过guava可以精确的对一个方法进行限流,基于令牌桶算法,我们通过AOP创建一个注解
首先引入坐标
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>28.0-jre</version> </dependency>
然后新建包结构

aspect下一个接口一个注解AccessLimit,一个AOP切面AccessLimitAop
AccessLimit内容为
package com.changgou.seckill.web.aspect; import java.lang.annotation.*; //自定义注解 //添加元注解,前三个通常是必备的 @Inherited //A类使用了此注解,B继承A,B继承这个注解 @Documented //生成javadoc时会标记注解,没有实质性的作用,不用关心 @Target({ElementType.FIELD,ElementType.METHOD,ElementType.TYPE}) //这个注解可以被注解到什么地方(field 字段、枚举的常量 method 方法 type 类、枚举、注解、接口) @Retention(RetentionPolicy.RUNTIME) //当前的注解不仅会保存在class文件中,并且jvm加载class后,该注解仍然存在 public @interface AccessLimit { }
AccessLimitAop为
package com.changgou.seckill.web.aspect; import com.alibaba.fastjson.JSON; import com.changgou.entity.Result; import com.changgou.entity.StatusCode; import com.google.common.util.concurrent.RateLimiter; 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.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component @Scope//默认为单例模式 常用的可选项为 singleton单例 prototype原型模式 @Aspect //声明为一个aop切面 public class AccessLimitAop { @Autowired private HttpServletResponse response; //这错不用管 //设置令牌的生成速率 //每秒生成两个,并存在桶中 private RateLimiter rateLimiter = RateLimiter.create(2.0); //配置一个切入点,切入点方法必须为public void 无参 无内容的方法,方法名就是id @Pointcut("@annotation(com.changgou.seckill.web.aspect.AccessLimit)") public void limit(){ } @Around("limit()") public Object around(ProceedingJoinPoint proceedingJoinPoint){ boolean flag = rateLimiter.tryAcquire(); Object obj = null; if(flag){ //允许访问 try { obj = proceedingJoinPoint.proceed(); } catch (Throwable throwable) { throwable.printStackTrace(); } }else { //拒绝访问 String errorMessage = JSON.toJSONString(new Result<>(false, StatusCode.ACCESSERROR,"fail")); //将信息返回到客户端 this.outMessage(response,errorMessage); } return obj; } private void outMessage(HttpServletResponse response,String errorMessage){ ServletOutputStream outputStream = null; try { response.setContentType("application/json;charset=utf-8"); outputStream = response.getOutputStream(); outputStream.write(errorMessage.getBytes("utf-8")); } catch (IOException e) { e.printStackTrace(); }finally { try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
使用时,只需将AccessLimit注解加载要限流的方法上即可
@RequestMapping("/add")
@AccessLimit //使用谷歌的guava自定义实现的微服务限流注解,目前限制为每秒最多访问两次
public Result add(@RequestParam("time")String time,@RequestParam("id")Long id,@RequestParam("random")String random){ .... }
1
1
浙公网安备 33010602011771号