Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use AOP+redis+lua to limit current

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)05/31 Report--

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 ()

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report