SpringBoot(三十六)SpringBoot使用sentinel自定义注解实现限流

前边我们学习了阿里的限流工具sentinel。她是有一个@SentinelResource注解可以使用的,但是呢,使用@SentinelResource注解需要链接sentinel控制台,在控制台中创建对应的规则。

再在对应的方法中使用@SentinelResource注解来配置功能。

但是呢,我这里有一个小小的尴尬,我目前使用的是springboot项目,而非springCloud,也可能是我配置的问题,连接sentinel控制台始终没有成功。

所以我就没有办法使用@SentinelResource注解了,但是我还不想使用其他方式来对方法进行限流,那怎么办呢?

很简单,我们之前学过自定义注解这个东西啊。

一:定义一个注解

java 复制代码
package com.modules.customannotations.myAnnotation;

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

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MySentinelResource
{
    // 可以定义一些属性,如果不需要,可以留空
    String resource();
    int number() default 1;// 这个可以不传参数
}

二:定义注解对应的切面类

java 复制代码
package com.modules.customannotations.annotationAspect;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.modules.customannotations.myAnnotation.MySentinelResource;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Aspect   // 声明该类为一个注解类;
@Component
public class MySentinelResourceAspect
{
    private final static Logger logger = LoggerFactory.getLogger(MyCustomAnnotationAspect.MyCustomAspect.class);

    // 自定义注解参数
    /**
     * 资源名称
     */
    private String resource;
    /**
     * 限流数量
     */
    private int number;

    // 以自定义 @MySentinelResource 注解为切点 --- @annotation里配置的 @MySentinelResource的自定义注解的全路径名
    @Pointcut("@annotation(com.modules.customannotations.myAnnotation.MySentinelResource)")
    public void mySentinelResourcePointcut() {}

    /**
     * 在切点之前,织入相关代码;
     * @param joinPoint
     * @param mySentinelResource
     */
    @Before("@annotation(mySentinelResource)")
    public void beforeMethod(JoinPoint joinPoint, MySentinelResource mySentinelResource) throws Exception
    {
        Entry ignored = null;
        try
        {
            // 获取注解的参数
            this.resource = mySentinelResource.resource();
            this.number = mySentinelResource.number();
            /* 1.创建存放限流规则的集合 */
            List<FlowRule> rules = new ArrayList<>();
            /* 2.创建限流规则 */
            FlowRule rule = new FlowRule();
            /* 定义资源,表示 Sentinel 会对哪个资源生效 "AddUser" */
            rule.setResource(resource);
            /* 定义限流的类型(此处使用 QPS 作为限流类型) */
            rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
            /* 定义 QPS 每秒通过的请求数 1 */
            rule.setCount(number);
            /* 3.将限流规则存放到集合中 */
            rules.add(rule);
            /* 4.加载限流规则 */
            FlowRuleManager.loadRules(rules);
            // 设置一个资源名称为 Hello
            ignored = SphU.entry(resource);
        }
        catch(Exception e)
        { // 被限流之后就会进入到这里来
            // 方法执行前的逻辑,终止程序执行可以通过抛出异常或其他方式实现
            throw new RuntimeException("别急,等一会在请求!");
        }
        finally
        { // 兜底方法,销毁资源
            // 销毁资源
            if (ignored != null)
            {
                ignored.exit();
            }
        }
    }

    /**
     * 环绕,可以在切入点前后织入代码,并且可以自由的控制何时执行切点;
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("mySentinelResourcePointcut()")
    private Object testAop(ProceedingJoinPoint point) throws Throwable
    {
        // 获取方法返回的数据
        Object obj = point.proceed();
        //System.out.println("obj:"+obj);
        return obj;
    }
}

这里我在做的时候钻牛角尖了,我在@Before注解定义的方法中对资源进行限流,但是呢,有一个小问题,这个方法是没有返回值的,也不能终止程序,这可怎么办呢?

后来我一寻思,这不傻了吗,我可以抛出异常啊,抛出异常程序不就停止了吗。

在结合我前边定义的全局异常处理类,直接这不就圆满了吗。

调用:

java 复制代码
@MySentinelResource(resource = "getData", number = 1) // 自定义注解:sentinel限流
public Map<String, Object> getData(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "") String search)
{
       Map<String, Object> result = indexService.getData(page, search);
}

到这里,使用sentinel自定义注解对请求限流就完成了。

有好的建议,请在下方输入你的评论。

相关推荐
一只大袋鼠几秒前
Spring 事务管理三种实现方式
java·数据库·spring·声明式事务
郝学胜-神的一滴6 分钟前
高并发秒杀系统设计全解:从需求拆解到Redis库存实战
java·数据库·redis·python·程序人生·缓存·php
NE_STOP10 分钟前
Redis--哨兵机制与CAP定理
java
书源丶12 分钟前
四十二、网络编程(上)——IP、端口与 UDP 编程
java·网络·tcp/ip·udp
m0_7108908713 分钟前
2026 年进销存系统大盘点:国内外 5 款主流进销存软件对比与选型指南
java·数据库·mysql
devilnumber15 分钟前
maven依赖的直接下载jar
java·maven
人道领域29 分钟前
【LeetCode刷题日记】二叉树层序遍历完全指南:从基础到LeetCode实战一篇搞定BFS模板,秒杀4道经典面试题
java·开发语言·数据结构·leetcode·面试·二叉树
承渊政道33 分钟前
CentOS 7部署Elasticsearch完整流程:避坑、基础操作、远程访问
java·linux·elasticsearch·系统架构·centos·远程工作·持续部署
咖啡八杯1 小时前
GoF设计模式——工厂方法模式
java·后端·设计模式
勿忘初心12211 小时前
SpringBoot 国密 SM4 配置加密(自动解密处理器实现)
spring boot·国密 sm4·自动解密处理器