使用注释AOP实现接口访问次数限制

前言

在日常开发工作中,我们常有接口会暴露出来,虽然我们增加了各种检验和拦截可以拦截大多数恶意访问,但是你不能保证对接方的猿子不会造出一个死循环来访问你的接口,尤其是我们的程序作为一个平台使用的时候,别人的一个误操作可能会造成服务器宕机,到时候成千上万的客户都会受到影响,所以在这种对接过程中一定要对对方的接口访问次数进行限制!这种方式可以理解为微服务中的服务降级!

安排栗子

新建一个注释类:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LimitTime {
	// 访问次数,默认为10次
	int time() default 10;
	// 过期时间,时间戳间隔
	long timeout() default 1;
}

定义一个存放调用信息的DTO:

@Data
public class LimitDTO {
    //最近一次刷新时间戳
	private Long refreshTime;
	//剩余访问次数
	private Integer time;
}

新建一个切面类:
注意在存储访问状态对象的时候一定要使用ConcurrentHashMap,此为线程安全的map,支持并发访问!

@Component
@Order
@Aspect
public class LimitTimeAspect {
	private ConcurrentHashMap<String, LimitDTO> limitMap = new ConcurrentHashMap<>();

	@Pointcut("@annotation(limitTime)")
	public void limit(LimitTime limitTime) {
	}

	@Around("limit(limitTime)")
	public Object aroundLog(ProceedingJoinPoint joinpoint, LimitTime limitTime) throws Throwable {
	    //获取传入的最大访问次数
		int time= limitKey.time();
		//获取计算时间
		long timeout = limitKey.timeout();
		//获取访问方法
		Object target = joinpoint.getTarget().getClass().getName();
		String key= target.toString();
		//如果第一次访问该方法
		if (limitMap.get(key) == null) {
		    //新建一次对象存放访问信息
			LimitDTO limitDTO=new LimitDTO();
			limitDTO.setTime(time- 1);
			limitDTO.setRefreshTime(new Date().getTime());
			limitMap.put(key, limitDTO);
		}else {
		    //如果不是第一次访问,获取上次访问的信息
			LimitDTO limitDTO=limitMap.get(key);
			//如果和上次刷新时间比已经过期
			if (new Date().getTime() - limitDTO.getRefreshTime() > timeout) {
			    //将对象中的刷新时间和访问次数刷新
				limitDTO.setRefreshTime(new Date().getTime());
				limitDTO.setTime(time);
				limitMap.put(key, limitDTO);
			}
			//获取当前访问对象中的剩余访问次数
			int t = (int) limitMap.get(key).getTime;
			//如果访问次数大于0
			if (t > 0) {
			    //允许访问,并将访问次数-1
				limitDTO.setTime(--t);
			} else {
			    //如果已经没有访问次数,返回错误信息
				ResultBO<Object> resultBO = new ResultBO<>();
				resultBO.setCode(1);
				resultBO.setMsg("已达最大访问次数");
				return resultBO;
			}
		}
		//打印信息
		System.err.println("剩余次数:" + limitMap.get(key).getTime + " 方法名称:" + key);
		return joinpoint.proceed();
	}

使用该注释:

@RequestMapping(value = "/sendCmd", method = RequestMethod.POST)
@ResponseBody
@LimitKey(time= 10, timeout = 10000)//10秒内可以访问10次
public int sendCmd(@RequestBody List<CmdDO> cmds) {
	//do something
	return new ResultBO<>();
}

测试:
在这里插入图片描述
在这里插入图片描述
撒花!完成!

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用Spring AOP实现接口访问量统计,可以按照以下步骤进行: 1. 定义一个注解@AccessCount,用于标记需要统计访问量的方法。 ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AccessCount { } ``` 2. 定义一个切面类AccessCountAspect,用于统计被@AccessCount标记的方法的访问量。这个类需要实现org.aspectj.lang.annotation.Aspect接口,并使用@Aspect注解标记。 ```java @Aspect @Component public class AccessCountAspect { private Map<String, Integer> accessCounts = new ConcurrentHashMap<>(); @Pointcut("@annotation(com.example.demo.annotation.AccessCount)") public void accessCountPointcut() {} @Around("accessCountPointcut()") public Object accessCountAround(ProceedingJoinPoint joinPoint) throws Throwable { String methodName = joinPoint.getSignature().toShortString(); int count = accessCounts.getOrDefault(methodName, 0); accessCounts.put(methodName, count + 1); return joinPoint.proceed(); } public Map<String, Integer> getAccessCounts() { return accessCounts; } } ``` 3. 在Spring配置文件中定义切面和切点。 ```xml <aop:aspectj-autoproxy/> <bean id="accessCountAspect" class="com.example.demo.aspect.AccessCountAspect"/> <aop:config> <aop:aspect ref="accessCountAspect"> <aop:pointcut id="accessCountPointcut" expression="execution(* com.example.demo.service..*(..))"/> <aop:around method="accessCountAround" pointcut-ref="accessCountPointcut"/> </aop:aspect> </aop:config> ``` 4. 在需要统计访问量的方法上添加@AccessCount注解。 ```java @Service public class UserServiceImpl implements UserService { @AccessCount @Override public User getUserById(Long id) { // ... } } ``` 5. 在需要获取访问量的地方,注入AccessCountAspect并调用getAccessCounts方法。 ```java @RestController @RequestMapping("/access-count") public class AccessCountController { @Autowired private AccessCountAspect accessCountAspect; @GetMapping("") public Map<String, Integer> getAccessCounts() { return accessCountAspect.getAccessCounts(); } } ``` 这样就可以使用Spring AOP实现接口访问量统计了。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值