您的位置:首页 > 游戏 > 手游 > 虚拟云手机 免费_北京企业网站seo平台_腾讯企点官网_重庆百度推广电话

虚拟云手机 免费_北京企业网站seo平台_腾讯企点官网_重庆百度推广电话

2025/5/24 0:49:02 来源:https://blog.csdn.net/weixin_45979122/article/details/146549621  浏览:    关键词:虚拟云手机 免费_北京企业网站seo平台_腾讯企点官网_重庆百度推广电话
虚拟云手机 免费_北京企业网站seo平台_腾讯企点官网_重庆百度推广电话

Java 实现 对外接口进行aop限流

1.需要的maven依赖

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

2.限流注解InterfaceLimit.java

特此注意: 这是一个注解类 @interface

package com.safesoft.config.customlimit;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;/*** [自定义接口限流注解]** @author Kevin.Wan* @date 2023/8/1**/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface InterfaceLimit {/*** 资源的key,唯一* 作用:不同的接口,不同的流量控制*/String key() default "";/*** 最多的访问限制次数*/double permitsPerSecond () ;/*** 获取令牌最大等待时间*/long timeout();/*** 获取令牌最大等待时间,单位(例:分钟/秒/毫秒) 默认:毫秒*/TimeUnit timeunit() default TimeUnit.MILLISECONDS;}

3.限流注解的切面类LimitAop.java

package com.safesoft.config.customlimit;import com.google.common.collect.Maps;
import com.google.common.util.concurrent.RateLimiter;
import com.safesoft.domain.utils.IPUtils;
import lombok.extern.slf4j.Slf4j;
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.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.util.WebUtils;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;import static com.safesoft.domain.common.Constants.DATE_TIME_FORMATTER;/*** [基于aop切面实现限流]** @author Kevin.Wan* @date 2023/8/1**/
@Slf4j
@Aspect
@Component
public class LimitAop {/*** 不同的接口,不同的流量控制* map的key为 Limiter.key*/private final Map<String, RateLimiter> limitMap = Maps.newConcurrentMap();@Around("@annotation(com.safesoft.config.customlimit.InterfaceLimit)")public Object around(ProceedingJoinPoint joinPoint) throws Throwable{//获取当前时间final String format_time = LocalDateTime.now().format(DATE_TIME_FORMATTER);MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();//拿limit的注解InterfaceLimit limit = method.getAnnotation(InterfaceLimit.class);if (limit != null) {//key作用:不同的接口,不同的流量控制String key=limit.key();RateLimiter rateLimiter = null;//验证缓存是否有命中keyif (!limitMap.containsKey(key)) {// 创建令牌桶rateLimiter = RateLimiter.create(limit.permitsPerSecond());limitMap.put(key, rateLimiter);log.info("新建了令牌桶={},容量={}",key,limit.permitsPerSecond());}rateLimiter = limitMap.get(key);// 拿令牌boolean acquire = rateLimiter.tryAcquire(limit.timeout(), limit.timeunit());//获取requestfinal HttpServletRequest request = getHttpServletRequest();// 请求的真实ipfinal String realIP = IPUtils.getRealIP(request);// 拿不到命令,直接返回异常提示if (!acquire) {log.error("当前请求人数过多进入等待,请求ip:{},请求时间:{}", realIP, format_time);throw new IllegalStateException("请求次数太频繁,请稍后...");}log.info("获取令牌成功,IP:{},时间:{}", realIP, format_time);}return joinPoint.proceed();}protected final HttpServletRequest getHttpServletRequest() {return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();}}

4.里面用到了获取访问IP工具类(可以不用)

package com.safesoft.domain.utils;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.servlet.http.HttpServletRequest;/*** @Author Sherlock.shen* @Date 2021/3/25 17:39* @Description: 获取访问ip工具类*/
public class IPUtils {private static final Logger LOGGER = LoggerFactory.getLogger(IPUtils.class);private static final String STR_UNKNOWN_LOWER_CASE = "unKnown";private static final String STR_COMMA = ",";public static final int NUM_ZERO = 0;public static final int NUM_ONE = 1;public static String getRealIP(HttpServletRequest request) {String ip = request.getHeader("x-forwarded-for");if (ip != null && ip.length() != NUM_ZERO && !STR_UNKNOWN_LOWER_CASE.equalsIgnoreCase(ip)) {// 多次反向代理后会有多个ip值,第一个ip才是真实ipif (ip.indexOf(STR_COMMA) != -NUM_ONE) {ip = ip.split(STR_COMMA)[NUM_ZERO];}}if (ip == null || ip.length() == NUM_ZERO || STR_UNKNOWN_LOWER_CASE.equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");LOGGER.info("Proxy-Client-IP ip,{}", ip);}if (ip == null || ip.length() == NUM_ZERO || STR_UNKNOWN_LOWER_CASE.equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");LOGGER.info("WL-Proxy-Client-IP,{}", ip);}if (ip == null || ip.length() == NUM_ZERO || STR_UNKNOWN_LOWER_CASE.equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_CLIENT_IP");LOGGER.info("HTTP_CLIENT_IP ip,{}", ip);}if (ip == null || ip.length() == NUM_ZERO || STR_UNKNOWN_LOWER_CASE.equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_X_FORWARDED_FOR");LOGGER.info("HTTP_X_FORWARDED_FOR,{}", ip);}if (ip == null || ip.length() == NUM_ZERO || STR_UNKNOWN_LOWER_CASE.equalsIgnoreCase(ip)) {ip = request.getHeader("X-Real-IP");LOGGER.info("X-Real-IP ip,{}", ip);}if (ip == null || ip.length() == NUM_ZERO || STR_UNKNOWN_LOWER_CASE.equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();LOGGER.info("getRemoteAddr ip,{}", ip);}return ip;}
}

5.然后就可以使用了 例如

/*** 水位监测看板数据==》也就是根据设备查询实时数据*/
@LogAction("对外水位监测看板数据")
@PostMapping(URLConstant.WATER_LEVEL_OPEN_MONITORING)
@InterfaceLimit(key = "getWaterLevel",permitsPerSecond = 5,timeout = 500,timeunit = TimeUnit.MILLISECONDS)
public JSONObject getWaterLevel(@RequestBody @Validated ExternalParam externalParam){LOGGER.info("对外接口-获取水位监测看板数据");//stop1 验签final Boolean aBoolean = externalService.signatureCheck(externalParam);if (aBoolean.equals(Boolean.FALSE)){throw new IllegalStateException("验签失败");}//stop2 判断是否有组编号String groupId = "";if (!Strings.isNullOrEmpty(externalParam.getGroupId())){groupId = externalParam.getGroupId();}//stop3 根据组编号查询设备实时数据return cockpitService.getWaterLevelRealTimeData(groupId);
}

其中 @InterfaceLimit(key = “getWaterLevel”,permitsPerSecond = 5,timeout = 500,timeunit = TimeUnit.MILLISECONDS) 这个就是

key任意起,不重复即可,,后面代表的是 每秒最多5个请求 每秒的前500毫秒响应

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com