限流

1.springboot集成redis

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

  application.properties配置

spring.redis.host=xxx
spring.redis.port=379
spring.redis.password=xx

2.RedisTemplate

@Configuration
public class RedisConfig {
	    @Bean
	    public RedisTemplate<String, Serializable> limitRedisTemplate(RedisConnectionFactory factory) {
	        RedisTemplate<String, Serializable> template = new RedisTemplate<>();
	        template.setKeySerializer(new StringRedisSerializer());
	        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
	        template.setConnectionFactory(factory);
	        return template;
	    }
	
}

3.软接口

@Target({ElementType.METHOD, ElementType.TYPE})
 @Retention(RetentionPolicy.RUNTIME)
 @Inherited
 @Documented
public @interface Limit {
	     String name() default "";
	
	     String key() default "";

	    String prefix() default "";
	
	     int period();

	     int count();
	
	     LimitType limitType() default LimitType.CUSTOMER;
}

4实现一个Aop

@Aspect
@Configuration
public class LimitInterceptor {
	 private static final Logger logger = LoggerFactory.getLogger(LimitInterceptor.class);
	 
	      private final RedisTemplate<String, Serializable> limitRedisTemplate;
	 
	      @Autowired
	      public LimitInterceptor(RedisTemplate<String, Serializable> limitRedisTemplate) {
	         this.limitRedisTemplate = limitRedisTemplate;
	      }
	      @Around("execution(public * *(..)) && @annotation(com.test.interfac.Limit)")
	      public Object interceptor(ProceedingJoinPoint pjp) {
	          MethodSignature signature = (MethodSignature) pjp.getSignature();
	          Method method = signature.getMethod();
	          Limit limitAnnotation = method.getAnnotation(Limit.class);
	          LimitType limitType = limitAnnotation.limitType();
	          String name = limitAnnotation.name();
	          String key;
	          int limitPeriod = limitAnnotation.period();
	          int limitCount = limitAnnotation.count();
	          switch (limitType) {
	              case IP:
	                  key = getIpAddress();
	                  break;
	            case CUSTOMER:
	                  key = limitAnnotation.key();
	                 break;
	             default:
	                  key = StringUtils.upperCase(method.getName());
	          }
	          System.out.println(key+"_---");
	          System.out.println(StringUtils.join(limitAnnotation.prefix(), key)+"=======");
	          ImmutableList<String> keys = ImmutableList.of(StringUtils.join(limitAnnotation.prefix(), key));
	         System.out.println(keys.toString()+"-00000000");
	          try {
	             String luaScript = buildLuaScript();
	              RedisScript<Number> redisScript = new DefaultRedisScript<>(luaScript, Number.class);
	             Number count = limitRedisTemplate.execute(redisScript, keys, limitCount, limitPeriod);
	              logger.info("Access try count is {} for name={} and key = {}", count, name, key);
	             if (count != null && count.intValue() <= limitCount) {
	                  return pjp.proceed();
	             } else {
	                  throw new RuntimeException("You have been dragged into the blacklist");
	              }
	          } catch (Throwable e) {
	              if (e instanceof RuntimeException) {
	                  throw new RuntimeException(e.getLocalizedMessage());
	              }
	              throw new RuntimeException("server exception");
	         }
	      }
	  
	      /**
	       * 限流 脚本
	       *
	       * @return lua脚本
	      */
	      public String buildLuaScript() {
	          StringBuilder lua = new StringBuilder();
	          lua.append("local c");
	          lua.append("\nc = redis.call('get',KEYS[1])");
	          // 调用不超过最大值,则直接返回
	          lua.append("\nif c and tonumber(c) > tonumber(ARGV[1]) then");
	          lua.append("\nreturn c;");
	          lua.append("\nend");
	          // 执行计算器自加
	          lua.append("\nc = redis.call('incr',KEYS[1])");
	          lua.append("\nif tonumber(c) == 1 then");
	          // 从第一次调用开始限流,设置对应键值的过期
	          lua.append("\nredis.call('expire',KEYS[1],ARGV[2])");
	          lua.append("\nend");
	          lua.append("\nreturn c;");
	          return lua.toString();
	      }
	  
	     private static final String UNKNOWN = "unknown";
	 
	     /**
	      * 获取IP地址
	     * @return
	      */
	     public String getIpAddress() {
	         HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
	         String ip = request.getHeader("x-forwarded-for");
	         if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
	             ip = request.getHeader("Proxy-Client-IP");
         }
	         if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
	             ip = request.getHeader("WL-Proxy-Client-IP");
	         }
	         if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
	             ip = request.getRemoteAddr();
	         }
	        return ip;
	     }
}

5.限流接口

	@RequestMapping(value="test",method = RequestMethod.GET)
    @Limit(key = "test", period = 60, count = 1, name="resource", prefix = "limit",limitType=LimitType.IP)
    public Object twodata() {
		 
		//masterMapper.insertUser();
		//slaveMapper.insertuser();
		return "dd";
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值