Java自定义注解+AOP

文章目录

  • 前言
  • 一、介绍
    • 1、注解
    • 2、AOP
  • 一、实现
    • 1、自定义注解
    • 2、滑动时间窗口算法
    • 3、定义切面类
  • 二、使用
    • 1、使用
    • 2、测试

前言

本文主要介绍如何定义实现注解,并配合AOP,来实现我们的滑动时间窗口算法

一、介绍

1、注解

注解(Annotation),是JDK5.0新增的,也叫元数据

其实就是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理
所以好处就是,我们使用注解,可以在不改变原有逻辑的情况下,补充一些逻辑

2、AOP

AOP,面向切面编程,也是可以帮助我们在不修改现有代码的情况下,对程序的功能进行拓展,往往用于实现日志处理,事务控制等通用功能

常用的通知类型

  • @Before:在 joinpoint 方法之前执行
  • @AfterReturning:在joinpoint 方法正常执行后执行
  • @AfterThrowing:在 joinpoint 方法抛出异常时执行
  • @After:在joinpoint 方法之后执行,无论方法正常还是异常退出
  • @Around:在joinpoint 之前和之后执行

一、实现

通过@interface关键字来定义注解
@Retention指定注解的生命周期,RetentionPolicy.RUNTIME表示在运行时有效
@Target指定作用目标ElementType.METHOD就是要加在方法上才有效
定义了两个参数period,limitCount,来实现我们的逻辑

1、自定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SlideWindowLimit {

	/**
	 * 限制时间范围,单位ms
	 */
	long period() default 1000;

	/**
	 * 限制请求次数
	 */
	int limitCount() default 5;
}

2、滑动时间窗口算法

主要Lua脚本来实现,另外还可以通过list和zset来实现,感兴趣的话,后面我再写一篇文章专门来分析

Java自定义注解+AOP_第1张图片

3、定义切面类

这里使用的是@Around环绕注解,目前只使用了前置增强,还可以使用后置增强,记录下调用等情况,感兴趣的话,大家可以实现下

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

@Aspect
@Component
public class SlideWindowLimitAspect {

	@Autowired
	private SlideWindowUtils slideWindowUtils;

	// 配置切入点
	@Pointcut("@annotation(cn.forlan.annotation.SlideWindowLimit)")
	public void slideWindowLimitPointcut() {
	}

	@Around("slideWindowLimitPointcut()")
	public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = attributes.getRequest();
		// 获取注解属性
		SlideWindowLimit slideWindowLimit = ((MethodSignature) pjp.getSignature()).getMethod().getAnnotation(SlideWindowLimit.class);
		if (slideWindowUtils.slideWindowAlgorithmByLua(request.getRequestURI(), slideWindowLimit.limitCount(), slideWindowLimit.period())) {
			return "操作过于频繁,请稍后重试";
		}
		return pjp.proceed();
	}

}

注:有多个增强类对同一方法进行增强,可以通过@Order(数字)可以设置优先级,数字越小,越先执行

二、使用

1、使用

上面定义的作用目标是方法,所以我们直接在方法上加自定义注解,@SlideWindowLimit(period = 10000, limitCount = 5),设置10秒内只能访问5次,如下图:
Java自定义注解+AOP_第2张图片

2、测试

我们通过Postman来快速调用5次,可以看到接口已经被限制,说明我们自定义的注解+AOP逻辑生效了
Java自定义注解+AOP_第3张图片

你可能感兴趣的:(框架,Java,java,spring,后端)