SpringBoot usa la memoria caché de Redis, combinada con Aop y anotaciones personalizadas para lograr la aceleración de la interfaz

La limitación de la interfaz es un requisito comercial durante el proceso de desarrollo para evitar que un solo módulo de microservicio experimente repentinamente demasiada simultaneidad y resulte en servicios de usuario irregulares, es decir, para lograr una cantidad fija de accesos a la misma interfaz dentro de un período de tiempo fijo.

Durante el proceso de desarrollo, redis generalmente se usa como caché para un almacenamiento rápido y una recuperación rápida. Los datos que requieren una gran cantidad de veces se pueden almacenar dentro de redis. ¿Podemos usar redis para lograr la aceleración de la interfaz?

Primero, hablemos de la anotación de anotación personalizada.

Sabemos que la estructura general de las anotaciones es:

@Target({ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@Repeatable
public @interface 注解名{
   类型 属性名() default 默认值,
    ...
}

 

TargetEs para especificar dónde se puede colocar esta anotación, METHODes decir, en el método, PARAMTERSen el parámetro, etc.

Retentiones la duración de la anotación especificada, RUNTIME>CLASS>SOURCE.

RepeatableSe refiere a si la anotación se puede reutilizar bajo la misma clase, método o atributo.

Cuando especificamos una anotación, podemos @注解名usarla directamente.

Segundo, hablemos de AOP nuevamente

Cuando estaba aprendiendo Spring antes, dije que hay dos formas de usar aop. Aquí describo principalmente cómo usar las anotaciones de aop. En primer lugar, si queremos usar aop, necesitamos tener dependencias de aop.

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>

El aspecto es una anotación de una clase de aspecto, y la clase marcada se convertirá en una clase de aspecto, en la que se pueden definir algunos puntos de corte y se pueden establecer mejoras como el borde delantero y trasero del punto de corte.

Código fuente de Aspect:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Aspect {
    String value() default "";
}

Agregue el formato de la expresión pointcut: execution(切入点方法修饰符 返回值类型 类的全限定名.方法名(..) ), que  representa todo.

3. Caso de aplicación: Realice una limitación de redis simulada

Después de importar primero las dependencias relevantes, escribimos anotaciones personalizadas @InCache:

/ ElementType.FIELD用于属性,ElementType.PARAMETER用于方法参数,ElementType.METHOD 用于方法
@Target({ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface InCache {
    String key() default "";
    int value() default 0;
}

En el futuro, esta clave y valor se pueden poner en el redis simulado. Por supuesto, el redis real agregará un parámetro de tiempo de caducidad al configurar setnx. Dado que aquí se usa el redis simulado, este parámetro de tiempo no se agregará concurrentMap.

Luego escribimos la interfaz básica y su clase de servicio:

//利用自定义注解和Aop对接口进行节流
@RestController
@CrossOrigin
public class UserController {
    @Resource
    UserServiceImpl userService;
 
    @GetMapping("login")
    @ResponseBody
    @InCache(key = "login",value = 3)
    public String login(){
        Integer value = AopUtil.redis.get("login");
        if (value == 0)
            return "访问次数刷完了,访问被refuse";
        return "第"+(4-value)+"次访问:"+userService.login("account", "password");
    }
}
 
 
@Component
public class UserServiceImpl {
 
    public String login(String account, String password) {
        if (account.equals("account") & password.equals("password")) {
            System.out.println("----------user login success -------");
            return "success";
        }else
            return "fail";
    }
}

A continuación, configuramos nuestro método de mejora de aop para el método de inicio de sesión en la clase de controlador:

@Aspect
@Component
@Slf4j
public class AopUtil {
    //代替redis
    public static ConcurrentMap<String,Integer> redis = new ConcurrentHashMap<>();
 
    //定义切入点并使用切面类方法代替
    @Pointcut("execution(public String com.example.aop.UserController.login())")
    public void interPoint(){}
 
    //利用前置增强检查注解
    @Before("interPoint()")
    public void checkAnnotation(JoinPoint joinPoint){
        //获取参数列表
        Object[] params =  joinPoint.getArgs();
        if (params.length != 0)
            System.out.println("切入方法的参数列表为:"+ Arrays.toString(Arrays.stream(params).toArray()));
        //获取方法,强行将签名对象类型转换成方法签名对象,仅用于在已知连接点类型为方法时使用
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        //根据注解类型获取注解数组,这个直接就是索引加注解对象,可获取注解的属性值
        InCache annotation = method.getAnnotation(InCache.class);
        if (annotation == null){
            System.out.println("该方法没有使用InCache注解!");
            return ;
        }
        String key = annotation.key();
 
        if(redis.containsKey(key)){
           log.info("缓存已存在此key,将value进行减一操作");
            Integer oldValue = redis.get(key);
            if (oldValue > 0){
                redis.remove(key);
                redis.put(key,oldValue-1);
            }else {
                log.info("缓存中的此key已经为0,拒绝接口访问数据库!");
            }
        }else {
            log.info("将key 与 value 存入缓存");
            redis.put(key,annotation.value());
        }
 
    }
 
}

De esta manera, se puede realizar el número básico de límite de veces.

Supongo que te gusta

Origin blog.csdn.net/zhangjiaming_zjm/article/details/130014257
Recomendado
Clasificación