Get the App
SLTechnology News&Howtos  ›  Development  › 

How to use AOP+redis+lua to limit current

Shulou Source: shulou.com Published: 2022-05-31 18:22:02 09月13日 Update

Most people do not understand the knowledge of this article "how to use AOP+redis+lua to limit current", so the editor summarizes the following content, detailed content, clear steps, and has a certain reference value. I hope you can get something after reading this article. Let's take a look at this "how to use AOP+redis+lua to do current limit" article.

Demand

The company uses OneByOne to delete data. In order to prevent too much data from being deleted within a period of time, let me limit the flow of an API. If an exception is reported when a certain threshold is exceeded, the deletion operation will be terminated.

Mode of realization

Create a custom annotation @ limit that allows users to configure count (maximum number of visits in a certain period of time) and period (given time range), that is, access frequency, where they need it. Then the request of the method is intercepted by LimitInterceptor and the access frequency is controlled by redis+lua script.

Source code Limit comments

Access frequency count, period used to configure the method

Import javax.validation.constraints.Min;import java.lang.annotation.*;@Target ({ElementType.METHOD, ElementType.TYPE}) @ Retention (RetentionPolicy.RUNTIME) @ Inherited@Documentedpublic @ interface Limit {/ * key * / String key () default ""; / * * Key prefix * / String prefix () default "" / * maximum number of visits within a certain period of time * / @ Min (1) int count (); / * given time range unit (seconds) * / @ Min (1) int period (); / * types of current restrictions (user-defined key or request ip) * / LimitType limitType () default LimitType.CUSTOMER;} LimitKey

Used to mark parameters as part of the redis key value

Import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target (ElementType.PARAMETER) @ Retention (RetentionPolicy.RUNTIME) public @ interface LimitKey {} LimitType

Enumeration, the type of redis key value, supports custom key and obtaining key from ip and methodName

Public enum LimitType {/ * Custom key * / CUSTOMER, / * requester IP * / IP, / * method name * / METHOD_NAME;} RedisLimiterHelper

Initialize a redisTemplate Bean used for current restriction

Import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;import org.springframework.data.redis.serializer.StringRedisSerializer;import java.io.Serializable;@Configurationpublic class RedisLimiterHelper {@ Bean public RedisTemplate limitRedisTemplate (@ Qualifier ("defaultStringRedisTemplate") StringRedisTemplate redisTemplate) {RedisTemplate template = new RedisTemplate () Template.setKeySerializer (new StringRedisSerializer ()); template.setValueSerializer (new GenericJackson2JsonRedisSerializer ()); template.setConnectionFactory (redisTemplate.getConnectionFactory ()); return template;}} LimitInterceptor

Use aop to intercept requests and control access frequency

Import com.google.common.collect.ImmutableList;import com.yxt.qida.api.bean.service.xxv2.openapi.anno.Limit;import com.yxt.qida.api.bean.service.xxv2.openapi.anno.LimitKey;import com.yxt.qida.api.bean.service.xxv2.openapi.anno.LimitType;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang3.ArrayUtils;import org.apache.commons.lang3.StringUtils;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around Import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.reflect.MethodSignature;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.script.DefaultRedisScript;import org.springframework.data.redis.core.script.RedisScript;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;import java.io.Serializable Import java.lang.annotation.Annotation;import java.lang.reflect.Method;@Slf4j@Aspect@Configurationpublic class LimitInterceptor {private static final String UNKNOWN = "unknown"; private final RedisTemplate limitRedisTemplate; @ Autowired public LimitInterceptor (RedisTemplate limitRedisTemplate) {this.limitRedisTemplate = limitRedisTemplate } @ Around ("execution (public * * (..)) & & @ annotation (com.yxt.qida.api.bean.service.xxv2.openapi.anno.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 (); int limitPeriod = limitAnnotation.period () Int limitCount = limitAnnotation.count (); / * get different key according to the current limit type. If you don't pass it, we will use the method name as key * / String key; switch (limitType) {case IP: key = getIpAddress (); break Case CUSTOMER: key = limitAnnotation.key (); break; case METHOD_NAME: String methodName = method.getName (); key = StringUtils.upperCase (methodName); break; default: throw new RuntimeException ("limitInterceptor-invalid enumeration value") } / * get the annotated key, which is the highest priority and overrides the previous key value * / Object [] args = pjp.getArgs (); Annotation [] [] paramAnnoAry = method.getParameterAnnotations (); for (Annotation [] item: paramAnnoAry) {int paramIndex = ArrayUtils.indexOf (paramAnnoAry, item) For (Annotation anno: item) {if (anno instanceof LimitKey) {Object arg = args [paramIndex]; if (arg instanceof String & & StringUtils.isNotBlank ((String) arg)) {key = (String) arg; break } if (StringUtils.isBlank (key)) {throw new RuntimeException ("limitInterceptor-key value cannot be empty");} String prefix = limitAnnotation.prefix (); String [] keyAry = StringUtils.isBlank (prefix)? New String [] {"limit", key}: new String [] {"limit", prefix, key}; ImmutableList keys = ImmutableList.of (StringUtils.join (keyAry, "-")); try {String luaScript = buildLuaScript (); RedisScript redisScript = new DefaultRedisScript (luaScript, Number.class); Number count = limitRedisTemplate.execute (redisScript, keys, limitCount, limitPeriod); if (count! = null & count.intValue ()

Tags: Content mode time frequency method annotation type data article times knowledge article scope control configuration difference highest that is value Apple Docker Huawei Linux macOS MariaDB Microsoft MySQL NVidia OPPO Reno Shulou Tech Info Apple Linux NVidia Xiaomi