O SpringBoot usa o cache Redis, combinado com Aop e anotações personalizadas para obter a otimização da interface

A otimização da interface é um requisito de negócios durante o processo de desenvolvimento para evitar que um único módulo de microsserviço experimente repentinamente muita simultaneidade e resulte em serviços de usuário instáveis, ou seja, para atingir um número fixo de acessos à mesma interface em um período de tempo fixo.

Durante o processo de desenvolvimento, o redis geralmente é usado como um cache para armazenamento e recuperação rápidos. Dados que exigem um grande número de vezes podem ser armazenados no redis, então podemos usar o redis para obter a otimização da interface?

Primeiro, vamos falar sobre a anotação de anotação personalizada

Sabemos que a estrutura geral das anotações é:

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

 

TargetServe para especificar onde essa anotação pode ser colocada, METHODou seja, no método, PARAMTERSno parâmetro e assim por diante.

Retentioné o tempo de vida da anotação especificada, RUNTIME>CLASS>SOURCE.

RepeatableRefere-se a se a anotação pode ser reutilizada na mesma classe, método ou propriedade.

Quando especificamos uma anotação, podemos @注解名usá-la diretamente.

Em segundo lugar, vamos falar sobre AOP novamente

Quando eu estava aprendendo Spring antes, eu disse que existem duas maneiras de usar o aop. Aqui eu descrevo principalmente como usar as anotações do aop. Primeiro de tudo, se quisermos usar o aop, precisamos ter dependências do aop.

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

Aspect é uma anotação de uma classe de aspecto, e a classe marcada se tornará uma classe de aspecto, na qual alguns pontos de corte podem ser definidos e aprimoramentos como borda frontal e traseira do ponto de corte podem ser definidos.

Código-fonte do Aspect:

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

Adicione o formato da expressão pointcut: execution(切入点方法修饰符 返回值类型 类的全限定名.方法名(..) ), que  representa tudo.

3. Caso de aplicação: Realize a limitação de redis simulada

Depois de importar as dependências relevantes, escrevemos anotações 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;
}

No futuro, esta chave e valor podem ser colocados no redis simulado. Obviamente, o redis real adicionará um parâmetro de tempo de expiração ao definir setnx. Como o redis simulado é usado aqui, esse parâmetro de tempo não será adicionado concurrentMap.

Em seguida, escrevemos a interface básica e sua classe de serviço:

//利用自定义注解和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";
    }
}

Em seguida, configuramos nosso método de aprimoramento aop para o método login na classe do 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());
        }
 
    }
 
}

Desta forma, o número básico de vezes limite pode ser realizado.

おすすめ

転載: blog.csdn.net/zhangjiaming_zjm/article/details/130014257