Spring Cloud Alibaba Sentinel集成

Posted 我是廖志伟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Cloud Alibaba Sentinel集成相关的知识,希望对你有一定的参考价值。

主项目链接:https://gitee.com/java_wxid/java_wxid
项目架构及博文总结:

项目模块:
前期规划,实现部分

java_wxid   
├── demo                                                            // 演示模块
│     └── 模块名称:apache-mybatis-demo模块                            //Apache Mybatis集成(已实现并有博文总结)
│     └── 模块名称:apache-shardingsphere-demo模块                     //Apache ShardingSphere集成(已实现并有博文总结)
│     └── 模块名称:design-demo模块                                    //设计模式实战落地(已实现并有博文总结)
│     └── 模块名称:elasticsearch-demo模块                             //ElasticSearch集成(已实现并有博文总结)
│     └── 模块名称:mongodb-demo模块                                   //MongoDB集成(已实现并有博文总结)
│     └── 模块名称:redis-demo模块                                     //Redis集成(已实现并有博文总结)
│     └── 模块名称:spring-boot-demo模块                               //Spring Boot快速构建应用(已实现并有博文总结)
│     └── 模块名称:spring-cloud-alibaba-nacos-demo模块                //Spring Cloud Alibaba Nacos集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-alibaba-seata-demo模块                //Spring Cloud Alibaba Seata集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-alibaba-sentinel-demo模块             //Spring Cloud Alibaba Sentinel集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-gateway-demo模块                      //Spring Cloud Gateway集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-hystrix-demo模块                      //Spring Cloud Hystrix集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-open-feign-demo模块                   //Spring Cloud Open Feign集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-ribbon-demo模块                       //Spring Cloud Ribbon集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-security-oauth2-demo模块              //Spring Cloud Security Oauth2集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-security-oauth2-sso-client-demo模块   //Spring Cloud Security Oauth2集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-skywalking-demo模块                   //Spring Cloud Skywalking集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-stream-demo模块                       //Spring Cloud Stream集成(已实现并有博文总结)
│     └── 模块名称:swagger-demo模块                                   //springfox-swagger2集成(已实现并有博文总结)
│     └── 模块名称:xxl-job模块                                        //xxl-job集成(已实现并有博文总结)
│     └── 模块名称:apache-spark-demo模块                              //Apache Spark集成
│     └── 模块名称:etl-hdfs-hive-hbase-demo模块                       //ETL、HDFS、Hive、Hbase集成
│     └── 模块名称:ddd-mode-demo模块                                  //DDD领域设计
│     └── 模块名称:netty-demo模块                                     //Netty集成
│     └── 模块名称:vue-demo模块                                       //前端vue集成
├── document                                                        // 文档
│     └── JavaKnowledgeDocument                                     //java知识点
│           └── java基础知识点.md                     
│           └── mq知识点.md
│           └── mysql知识点.md
│           └── redis知识点.md
│           └── springcould知识点.md
│           └── spring知识点.md
│     └── FounderDocument                                           //创始人
│           └── 创始人.md

系列文章:快速集成各种微服务相关的技术,帮助大家可以快速集成到自己的项目中,节约开发时间。
提示:系列文章还未全部完成,后续的文章,会慢慢补充进去的。

文章目录

创建spring-cloud-alibaba-sentinel-demo项目

项目代码:https://gitee.com/java_wxid/java_wxid/tree/master/demo/spring-cloud-alibaba-sentinel-demo
项目结构如下(示例):

修改pom.xml

代码如下(示例):

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>


    <groupId>com.example</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-cloud-alibaba-sentinel-demo</name>
    <description>Demo project for Spring Boot</description>

    <!--    属性配置-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <!--引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。
        在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系-->
        <spring.boot.version>2.3.12.RELEASE</spring.boot.version>
        <spring.cloud.version>Hoxton.SR12</spring.cloud.version>
        <spring.cloud.alibaba.version>2.2.7.RELEASE</spring.cloud.alibaba.version>
    </properties>

    <dependencies>
        <!--        代表web模块,在这个模块中含了许多JAR包,有spring相关的jar,内置tomcat服务器,jackson等,这些web项目中常用的的功能都会自动引入-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.4.5</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.4.1</version>
        </dependency>

        <!--        druid驱动-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.23</version>
        </dependency>
        <!--        mysql连接-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.22</version>
        </dependency>
        <!--        mybatis的一个库-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.2</version>
        </dependency>

        <!-- Alibaba Nacos 配置 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--        在SpringBoot 2.4.x的版本之后,对于bootstrap.properties/bootstrap.yaml配置文件(我们合起来成为Bootstrap配置文件)的支持,其实这个jar包里什么都没有,就只有一个标识类Marker,用来标识要开启Bootstrap配置文件的支持,由于父类用了2.5.6版本需要导入如下的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
            <version>3.1.0</version>
        </dependency>

        <!--openfeign客户端依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-openfeign-core</artifactId>
            <version>2.2.6.RELEASE</version>
        </dependency>
        <!--引入HttpClient依赖-->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>
        <!-- 引入Feign Slf4j -->
        <dependency>
            <groupId>com.netflix.feign</groupId>
            <artifactId>feign-slf4j</artifactId>
            <version>8.14.4</version>
        </dependency>
        <!--        lombok插件-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>


<!--        @SentinelResource 注解用来标识资源是否被限流、降级。

        blockHandler: 定义当资源内部发生了BlockException应该进入的方法(捕获的是Sentinel定义的异常)
        fallback: 定义的是资源内部发生了Throwable应该进入的方法
        exceptionsToIgnore:配置fallback可以忽略的异常
        源码入口:com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-annotation-aspectj</artifactId>
            <version>1.8.0</version>
        </dependency>

<!--        流控规则设置可以通过Sentinel dashboard配置
        客户端需要引入 Transport 模块来与 Sentinel 控制台进行通信。-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-transport-simple-http</artifactId>
            <version>1.8.0</version>
        </dependency>

        <!--- 解决流控链路不生效的问题
        从1.6.3版本开始,Sentinel Web filter默认收敛所有URL的入口context,导致链路限流不生效。
        从1.7.0版本开始,官方在CommonFilter引入了WEB_CONTEXT_UNIFY参数,用于控制是否收敛context,将其配置为false即可根据不同的URL进行链路限流。
        1.8.0 需要引入sentinel-web-servlet依赖
        -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-web-servlet</artifactId>
        </dependency>

        <!-- Spring Cloud Alibaba整合Sentinel -->

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <!--sentinel持久化 采用 Nacos 作为规则配置数据源-->
<!--        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>-->
    </dependencies>


    <!--
        引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。
        在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系
     -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>$spring.boot.version</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>$spring.cloud.version</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>$spring.cloud.alibaba.version</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

修改SpringCloudAlibabaSentinelDemoApplication

代码如下(示例):

package com.example.springcloudalibabasentineldemo;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@MapperScan("com.example.springcloudalibabasentineldemo.dao")
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class SpringCloudAlibabaSentinelDemoApplication 

    public static void main(String[] args) 
        SpringApplication.run(SpringCloudAlibabaSentinelDemoApplication.class, args);
    




创建bootstrap.yml

代码如下(示例):

#bootstrap.yml优先级比application.yml优先级高
spring:
  #prefix−spring.profile.active.$file-extension
  #nacos会根据当前环境去拼接配置名称查找相应配置文件,
  #示例:spring.application.name-spring.profiles.active-spring.cloud.nacos.config.file-extension
  #获取到值:nacos-autoconfig-service-dev.yml
  profiles:
    #开发环境dev,测试环境test,生产环境prod
    active: dev
  application:
    #配置应用的名称,用于获取配置
    name: spring-cloud-alibaba-sentinel-demo
  cloud:
    nacos:
      discovery:
        # 服务注册地址
        server-addr: 106.14.132.94:8848
      config:
        #nacos配置中心地址
        server-addr: 106.14.132.94:8848
        #配置中心的命名空间id
        namespace: 9e50b6d9-6c3d-4e7a-b701-10f085e4b98d
        #配置分组,默认没有也可以
        group: DEFAULT_GROUP
        #配置文件后缀,用于拼接配置配置文件名称,目前只支持yaml和properties
        file-extension: yaml
        #配置自动刷新
        refresh-enabled: true
        #配置文件的前缀,默认是application.name的值,如果配了prefix,就取prefix的值
        #prefix: nacos-autoconfig-service-$spring.profile.active
        # 配置编码
        encode: UTF-8
        username: nacos
        password: nacos


创建application.yml

代码如下(示例):

server:
  port: 8095
#暴露actuator端点   http://localhost:8800/actuator/sentinel
management:
  endpoints:
    web:
      exposure:
        include: '*'
spring:
  application:
    name: mall-user-sentinel-demo
  cloud:
    sentinel:
      transport:
        # 添加sentinel的控制台地址
        dashboard: 127.0.0.1:8080
        # 指定应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer
        #port: 8719
  #      datasource:
  #        ds1:
  #          nacos:
  #            server-addr: 127.0.0.1:8848
  #            dataId: $spring.application.name
  #            groupId: DEFAULT_GROUP
  #            data-type: json
  #            rule-type: flow
  #数据库配置
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://139.224.137.74:3306/syncdemo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: root
    password: ca0a997ee4770063
#mybatis
mybatis-plus:
  mapper-locations: classpath*:/mapper/*.xml
  #实体扫描,多个package用逗号或者分号分隔
  typeAliasesPackage: com.example.springcloudalibabasentineldemo.entity







创建SentinelConfig

代码如下(示例):

package com.example.springcloudalibabasentineldemo.config;


import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
import com.example.springcloudalibabasentineldemo.sentinel.MyUrlBlockHandler;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


/**
 * @className: SentinelConfig
 * @description: https://github.com/alibaba/Sentinel/issues/1213
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
@Configuration
public class SentinelConfig 

    @Bean
    public FilterRegistrationBean sentinelFilterRegistration() 
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new CommonFilter());
        registration.addUrlPatterns("/*");
        // 入口资源关闭聚合  解决流控链路不生效的问题
        registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
        registration.setName("sentinelFilter");
        registration.setOrder(1);

        //CommonFilter的BlockException自定义处理逻辑
        WebCallbackManager.setUrlBlockHandler(new MyUrlBlockHandler());

        //解决授权规则不生效的问题
        //com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser
        //WebCallbackManager.setRequestOriginParser(new MyRequestOriginParser());

        return registration;
    



创建HelloController

代码如下(示例):

package com.example.springcloudalibabasentineldemo.controller;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.slots.block.BlockException;
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 lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
@RestController
@Slf4j
public class HelloController 

    private static final String RESOURCE_NAME = "hello";

    @RequestMapping(value = "/hello")
    public String hello() 

        Entry entry = null;
        try 
            // 资源名可使用任意有业务语义的字符串,比如方法名、接口名或其它可唯一标识的字符串。
            entry = SphU.entry(RESOURCE_NAME);
            // 被保护的业务逻辑
            String str = "hello world";
            log.info("====="+str+"=====");
            return str;
         catch (BlockException e1) 
            // 资源访问阻止,被限流或被降级
            //进行相应的处理操作
            log.info("block!");
            return "被流控了!";
         catch (Exception ex) 
            // 若需要配置降级规则,需要通过这种方式记录业务异常
            Tracer.traceEntry(ex, entry);
         finally 
            if (entry != null) 
                entry.exit();
            
        
        return null;
    

    /**
     * 定义流控规则
     */
    @PostConstruct
    private static void initFlowRules()
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        //设置受保护的资源
        rule.setResource(RESOURCE_NAME);
        // 设置流控规则 QPS
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 设置受保护的资源阈值
        // Set limit QPS to 20.
        rule.setCount(1);
        rules.add(rule);
        // 加载配置好的规则
        FlowRuleManager.loadRules(rules);
    

创建LimitFlowController

代码如下(示例):

package com.example.springcloudalibabasentineldemo.controller;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.springcloudalibabasentineldemo.entity.UserEntity;
import com.example.springcloudalibabasentineldemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
@RestController
public class LimitFlowController 

    @RequestMapping("/test")
//    @SentinelResource(value = "test",blockHandlerClass = CommonBlockHandler.class,blockHandler = "handleException3")
    public String test() 

        try 
            Thread.sleep(100);
         catch (InterruptedException e) 
            e.printStackTrace();
        

        return "========test()========";
    

    AtomicInteger atomicInteger = new AtomicInteger();

    @RequestMapping("/test2")
    public String test2() 
        atomicInteger.getAndIncrement();
        if (atomicInteger.get() % 2 == 0)
            //模拟异常和异常比率
            int i = 1/0;
        

        return "========test2()========";
    

    @Autowired
    private UserService userService;

    @RequestMapping(value = "/test3")  //CommonFilter
    public UserEntity test3() 
        UserEntity user = userService.getUser(1);
        return user;
    

    @RequestMapping(value = "/test4")
    public UserEntity test4() 
        UserEntity user = userService.getUser(1);
        return user;
    


    public String handleException(BlockException exception) 
        return "===被限流降级啦===";
    


创建UserController

代码如下(示例):

package com.example.springcloudalibabasentineldemo.controller;


import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.springcloudalibabasentineldemo.entity.UserEntity;
import com.example.springcloudalibabasentineldemo.feign.OrderFeignService;
import com.example.springcloudalibabasentineldemo.sentinel.CommonBlockHandler;
import com.example.springcloudalibabasentineldemo.sentinel.CommonFallback;
import com.example.springcloudalibabasentineldemo.service.UserService;
import com.example.springcloudalibabasentineldemo.utils.PageUtils;
import com.example.springcloudalibabasentineldemo.utils.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.Map;


/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
@RestController
@RequestMapping(value = "/user")
public class UserController 
    @Autowired
    private UserService userService;

    @Autowired
    OrderFeignService orderFeignService;

    @RequestMapping(value = "/getNacosConfigure")
    @SentinelResource(value = "getNacosConfigure",
            blockHandlerClass = CommonBlockHandler.class,
            blockHandler = "getNacosConfigure",
            fallbackClass = CommonFallback.class,
            fallback = "getNacosConfigure"
    )
    public String getNacosConfigure() 
//        try 
//            // 模拟测试并发线程数限流
//            Thread.sleep(900);
//         catch (InterruptedException e) 
//            e.printStackTrace();
//        
        
        // findOrderByUserId  限流规则  2    sentinel dashboard 定义规则

        //feign调用
        String result = orderFeignService.getNacosConfigure();
        return result;
    


    /**
     * 列表
     */
    @RequestMapping("/list")
    @SentinelResource(value = "userlist",
            blockHandlerClass = CommonBlockHandler.class,
            blockHandler = "handleException",fallback = "fallback")
    public R list(@RequestParam Map<String, Object> params)
        PageUtils page = userService.queryPage(params);
       // int i=1/0;

        return R.ok().put("page", page);
    

    public R handleException(@RequestParam Map<String, Object> params,BlockException exception)
        return R.error(-1,"===被限流降级啦===");
    


    /**
     * 信息
     */
    @RequestMapping("/info/id")
    @SentinelResource(value = "userinfo",
            blockHandlerClass = CommonBlockHandler.class,
            blockHandler = "handleException2",
            fallbackClass = CommonFallback.class,
            fallback = "fallback"
    )
    public R info(@PathVariable("id") Integer id)
		UserEntity user = userService.getById(id);

		if(id==4)
		    throw new IllegalArgumentException("异常参数");
        

        return R.ok().put("mapper", user);
    

    public R handleException2(@PathVariable("id") Integer id, BlockException exception)
        return R.error(-1,"===被限流降级啦===");
    
    public R fallback(@PathVariable("id") Integer id,Throwable e)
        return R.error(-1,"===被熔断降级啦==="+e.getMessage());
    

    /**
     * 保存
     */
    @RequestMapping("/save")
    public R save(@RequestBody UserEntity user)
		userService.save(user);
        return R.ok();
    

    /**
     * 修改
     */
    @RequestMapping("/update")
    public R update(@RequestBody UserEntity user)
		userService.updateById(user);

        return R.ok();
    

    /**
     * 删除
     */
    @RequestMapping("/delete")
    public R delete(@RequestBody Integer[] ids)
		userService.removeByIds(Arrays.asList(ids));

        return R.ok();
    



创建UserDao

代码如下(示例):

package com.example.springcloudalibabasentineldemo.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.springcloudalibabasentineldemo.entity.UserEntity;
import org.apache.ibatis.annotations.Mapper;

/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
@Mapper
public interface UserDao extends BaseMapper<UserEntity> 
	


创建AuthorityDemo

代码如下(示例):

package com.example.springcloudalibabasentineldemo.demo;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;

import java.util.Collections;

/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class AuthorityDemo 
    private static final String RESOURCE_NAME = "testABC";

    public static void main(String[] args) 
        System.out.println("========Testing for black list========");
        initBlackRules();
        testFor(RESOURCE_NAME, "appA");
        testFor(RESOURCE_NAME, "appB");
        testFor(RESOURCE_NAME, "appC");
        testFor(RESOURCE_NAME, "appE");

        System.out.println("========Testing for white list========");
        initWhiteRules();
        testFor(RESOURCE_NAME, "appA");
        testFor(RESOURCE_NAME, "appB");
        testFor(RESOURCE_NAME, "appC");
        testFor(RESOURCE_NAME, "appE");
    

    private static void testFor(/*@NonNull*/ String resource, /*@NonNull*/ String origin) 
        ContextUtil.enter(resource, origin);
        Entry entry = null;
        try 
            entry = SphU.entry(resource);
            System.out.println(String.format("Passed for resource %s, origin is %s", resource, origin));
         catch (BlockException ex) 
            System.err.println(String.format("Blocked for resource %s, origin is %s", resource, origin));
         finally 
            if (entry != null) 
                entry.exit();
            
            ContextUtil.exit();
        
    

    private static void initWhiteRules() 
        AuthorityRule rule = new AuthorityRule();
        rule.setResource(RESOURCE_NAME);
        rule.setStrategy(RuleConstant.AUTHORITY_WHITE);
        rule.setLimitApp("appA,appE");
        AuthorityRuleManager.loadRules(Collections.singletonList(rule));
    

    private static void initBlackRules() 
        AuthorityRule rule = new AuthorityRule();
        rule.setResource(RESOURCE_NAME);
        rule.setStrategy(RuleConstant.AUTHORITY_BLACK);
        rule.setLimitApp("appA,appB");
        AuthorityRuleManager.loadRules(Collections.singletonList(rule));
    


创建FlowThreadDemo

代码如下(示例):

package com.example.springcloudalibabasentineldemo.demo;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
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.alibaba.csp.sentinel.util.TimeUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class FlowThreadDemo 

    private static AtomicInteger pass = new AtomicInteger();
    private static AtomicInteger block = new AtomicInteger();
    private static AtomicInteger total = new AtomicInteger();
    private static AtomicInteger activeThread = new AtomicInteger();

    private static volatile boolean stop = false;
    private static final int threadCount = 100;

    private static int seconds = 60 + 40;
    private static volatile int methodBRunningTime = 2000;

    public static void main(String[] args) throws Exception 
        System.out.println(
                "MethodA will call methodB. After running for a while, methodB becomes fast, "
                        + "which make methodA also become fast ");
        tick();
        initFlowRule();

        for (int i = 0; i < threadCount; i++) 
            Thread entryThread = new Thread(new Runnable() 
                @Override
                public void run() 
                    while (true) 
                        Entry methodA = null;
                        try 
                            TimeUnit.MILLISECONDS.sleep(5);
                            methodA = SphU.entry("methodA");
                            activeThread.incrementAndGet();
                            Entry methodB = SphU.entry("methodB");
                            TimeUnit.MILLISECONDS.sleep(methodBRunningTime);
                            methodB.exit();
                            pass.addAndGet(1);
                         catch (BlockException e1) 
                            block.incrementAndGet();
                         catch (Exception e2) 
                            // biz exception
                         finally 
                            total.incrementAndGet();
                            if (methodA != null) 
                                methodA.exit();
                                activeThread.decrementAndGet();
                            
                        
                    
                
            );
            entryThread.setName("working thread");
            entryThread.start();
        
    

    private static void initFlowRule() 
        List<FlowRule> rules = new ArrayList<FlowRule>();
        FlowRule rule1 = new FlowRule();
        rule1.setResource("methodA");
        // set limit concurrent thread for 'methodA' to 20
        rule1.setCount(20);
        rule1.setGrade(RuleConstant.FLOW_GRADE_THREAD);
        rule1.setLimitApp("default");

        rules.add(rule1);
        FlowRuleManager.loadRules(rules);
    

    private static void tick() 
        Thread timer = new Thread(new TimerTask());
        timer.setName("sentinel-timer-task");
        timer.start();
    

    static class TimerTask implements Runnable 

        @Override
        public void run() 
            long start = System.currentTimeMillis();
            System.out.println("begin to statistic!!!");

            long oldTotal = 0;
            long oldPass = 0;
            long oldBlock = 0;

            while (!stop) 
                try 
                    TimeUnit.SECONDS.sleep(1);
                 catch (InterruptedException e) 
                
                long globalTotal = total.get();
                long oneSecondTotal = globalTotal - oldTotal;
                oldTotal = globalTotal;

                long globalPass = pass.get();
                long oneSecondPass = globalPass - oldPass;
                oldPass = globalPass;

                long globalBlock = block.get();
                long oneSecondBlock = globalBlock - oldBlock;
                oldBlock = globalBlock;
    
                System.out.println(seconds + " total qps is: " + oneSecondTotal);
                System.out.println(TimeUtil.currentTimeMillis() + ", total:" + oneSecondTotal
                        + ", pass:" + oneSecondPass
                        + ", block:" + oneSecondBlock
                        + " activeThread:" + activeThread.get());
                if (seconds-- <= 0) 
                    stop = true;
                
                if (seconds == 40) 
                    System.out.println("method B is running much faster; more requests are allowed to pass");
                    methodBRunningTime = 20;
                
            

            long cost = System.currentTimeMillis() - start;
            System.out.println("time cost: " + cost + " ms");
            System.out.println("total:" + total.get() + ", pass:" + pass.get()
                    + ", block:" + block.get());
            System.exit(0);
        
    


创建PaceFlowDemo

代码如下(示例):

package com.example.springcloudalibabasentineldemo.demo;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
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.alibaba.csp.sentinel.util.TimeUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class PaceFlowDemo 
    private static final String KEY = "abc";

    private static volatile CountDownLatch countDown;

    private static final Integer requestQps = 100;
    private static final Integer count = 10;
    private static final AtomicInteger done = new AtomicInteger();
    private static final AtomicInteger pass = new AtomicInteger();
    private static final AtomicInteger block = new AtomicInteger();

    public static void main(String[] args) throws InterruptedException 
        System.out.println("pace behavior");
        countDown = new CountDownLatch(1);
        initPaceFlowRule();
        simulatePulseFlow();
        countDown.await();

        System.out.println("done");
        System.out.println("total pass:" + pass.get() + ", total block:" + block.get());

        System.out.println();
        System.out.println("default behavior");
        TimeUnit.SECONDS.sleep(5);
        done.set(0);
        pass.set(0);
        block.set(0);
        countDown = new CountDownLatch(1);
        initDefaultFlowRule();
        simulatePulseFlow();
        countDown.await();
        System.out.println("done");
        System.out.println("total pass:" + pass.get() + ", total block:" + block.get());
        System.exit(0);
    

    private static void initPaceFlowRule() 
        List<FlowRule> rules = new ArrayList<FlowRule>();
        FlowRule rule1 = new FlowRule();
        rule1.setResource(KEY);
        rule1.setCount(count);
        rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule1.setLimitApp("default");
        /*
         * CONTROL_BEHAVIOR_RATE_LIMITER means requests more than threshold will be queueing in the queue,
         * until the queueing time is more than @link FlowRule#maxQueueingTimeMs, the requests will be rejected.
         */
        rule1.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER);
        rule1.setMaxQueueingTimeMs(20 * 1000);

        rules.add(rule1);
        FlowRuleManager.loadRules(rules);
    

    private static void initDefaultFlowRule() 
        List<FlowRule> rules = new ArrayList<FlowRule>();
        FlowRule rule1 = new FlowRule();
        rule1.setResource(KEY);
        rule1.setCount(count);
        rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule1.setLimitApp("default");
        // CONTROL_BEHAVIOR_DEFAULT means requests more than threshold will be rejected immediately.
        rule1.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);

        rules.add(rule1);
        FlowRuleManager.loadRules(rules);
    

    private static void simulatePulseFlow() 
        for (int i = 0; i < requestQps; i++) 
            Thread thread = new Thread(new Runnable() 
                @Override
                public void run() 
                    long startTime = TimeUtil.currentTimeMillis();
                    Entry entry = null;
                    try 
                        entry = SphU.entry(KEY);
                     catch (BlockException e1) 
                        block.incrementAndGet();
                     catch (Exception e2) 
                        // biz exception
                     finally 
                        if (entry != null) 
                            entry.exit();
                            pass.incrementAndGet();
                            long cost = TimeUtil.currentTimeMillis() - startTime;
                            System.out.println(
                                    TimeUtil.currentTimeMillis() + " one request pass, cost " + cost + " ms");
                        
                    

                    try 
                        TimeUnit.MILLISECONDS.sleep(5);
                     catch (InterruptedException e1) 
                        // ignore
                    

                    if (done.incrementAndGet() >= requestQps) 
                        countDown.countDown();
                    
                
            , "Thread " + i);
            thread.start();
        
    


创建SystemGuardDemo

代码如下(示例):

package com.example.springcloudalibabasentineldemo.demo;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.alibaba.csp.sentinel.util.TimeUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class SystemGuardDemo 

    private static AtomicInteger pass = new AtomicInteger();
    private static AtomicInteger block = new AtomicInteger();
    private static AtomicInteger total = new AtomicInteger();

    private static volatile boolean stop = false;
    private static final int threadCount = 100;

    private static int seconds = 60 + 40;

    public static void main(String[] args) throws Exception 

        tick();
        initSystemRule();

        for (int i = 0; i < threadCount; i++) 
            Thread entryThread = new Thread(new Runnable() 
                @Override
                public void run() 
                    while (true) 
                        Entry entry = null;
                        try 
                            entry = SphU.entry("methodA", EntryType.IN);
                            pass.incrementAndGet();
                            try 
                                TimeUnit.MILLISECONDS.sleep(20);
                             catch (InterruptedException e) 
                                // ignore
                            
                         catch (BlockException e1) 
                            block.incrementAndGet();
                            try 
                                TimeUnit.MILLISECONDS.sleep(20);
                             catch (InterruptedException e) 
                                // ignore
                            
                         catch (Exception e2) 
                            // biz exception
                         finally 
                            total.incrementAndGet();
                            if (entry != null) 
                                entry.exit();
                            
                        
                    
                

            );
            entryThread.setName("working-thread");
            entryThread.start();
        
    

    private static void initSystemRule() 
        List<SystemRule> rules = new ArrayList<SystemRule>();
        SystemRule rule = new SystemRule();
        // max load is 3
        rule.setHighestSystemLoad(3.0);
        // max cpu usage is 60%
        rule.setHighestCpuUsage(0.6);
        // max avg rt of all request is 10 ms
        rule.setAvgRt(10);
        // max total qps is 20
        rule.setQps(20);
        // max parallel working thread is 10
        rule.setMaxThread(10);

        rules.add(rule);
        SystemRuleManager.loadRules(Collections.singletonList(rule));
    

    private static void tick() 
        Thread timer = new Thread(new TimerTask());
        timer.setName("sentinel-timer-task");
        timer.start();
    

    static class TimerTask implements Runnable 
        @Override
        public void run() 
            System.out.println("begin to statistic!!!");
            long oldTotal = 0;
            long oldPass = 0;
            long oldBlock = 0;
            while (!stop) 
                try 
                    TimeUnit.SECONDS.sleep(1);
                 catch (InterruptedException e) 
                
                long globalTotal = total.get();
                long oneSecondTotal = globalTotal - oldTotal;
                oldTotal = globalTotal;

                long globalPass = pass.get();
                long oneSecondPass = globalPass - oldPass;
                oldPass = globalPass;

                long globalBlock = block.get();
                long oneSecondBlock = globalBlock - oldBlock;
                oldBlock = globalBlock;

                System.out.println(seconds + ", " + TimeUtil.currentTimeMillis() + ", total:"
                    + oneSecondTotal + ", pass:"
                    + oneSecondPass + ", block:" + oneSecondBlock);
                if (seconds-- <= 0) 
                    stop = true;
                
            
            System.exit(0);
        
    

创建WarmUpFlowDemo

代码如下(示例):

package com.example.springcloudalibabasentineldemo.demo;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
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.alibaba.csp.sentinel.util.TimeUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class WarmUpFlowDemo 
    private static final String KEY = "abc";

    private static AtomicInteger pass = new AtomicInteger();
    private static AtomicInteger block = new AtomicInteger();
    private static AtomicInteger total = new AtomicInteger();

    private static volatile boolean stop = false;

    private static final int threadCount = 100;
    private static int seconds = 60 + 40;

    public static void main(String[] args) throws Exception 
        initFlowRule();
        // trigger Sentinel internal init
        Entry entry = null;
        try 
            entry = SphU.entry(KEY);
         catch (Exception e) 
         finally 
            if (entry != null) 
                entry.exit();
            
        

        Thread timer = new Thread(new TimerTask());
        timer.setName("sentinel-timer-task");
        timer.start();

        //first make the system run on a very low condition
        for (int i = 0; i < 3; i++) 
            Thread t = new Thread(new WarmUpTask());
            t.setName("sentinel-warmup-task");
            t.start();
        
        Thread.sleep(20000);

        /*
         * Start more thread to simulate more qps. Since we use @link RuleConstant.CONTROL_BEHAVIOR_WARM_UP as
         * @link FlowRule#controlBehavior, real passed qps will increase to @link FlowRule#count in
         * @link FlowRule#warmUpPeriodSec seconds.
         */
        for (int i = 0; i < threadCount; i++) 
            Thread t = new Thread(new RunTask());
            t.setName("sentinel-run-task");
            t.start();
        
    

    private static void initFlowRule() 
        List<FlowRule> rules = new ArrayList<FlowRule>();
        FlowRule rule1 = new FlowRule();
        rule1.setResource(KEY);
        rule1.setCount(20);
        rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule1.setLimitApp("default");
        rule1.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
        rule1.setWarmUpPeriodSec(10);

        rules.add(rule1);
        FlowRuleManager.loadRules(rules);
    

    static class WarmUpTask implements Runnable 
        @Override
        public void run() 
            while (!stop) 
                Entry entry = null;
                try 
                    entry = SphU.entry(KEY);
                    // token acquired, means pass
                    pass.addAndGet(1);
                 catch (BlockException e1) 
                    block.incrementAndGet();
                 catch (Exception e2) 
                    // biz exception
                 finally 
                    total.incrementAndGet();
                    if (entry != null) 
                        entry.exit();
                    
                
                Random random2 = new Random();
                try 
                    TimeUnit.MILLISECONDS.sleep(random2.nextInt(2000));
                 catch (InterruptedException e) 
                    // ignore
                
            
        
    

    static class RunTask implements Runnable 
        @Override
        public void run() 
            while (!stop) 
                Entry entry = null;
                try 
                    entry = SphU.entry(KEY);
                    pass.addAndGet(1);
                 catch (BlockException e1) 
                    block.incrementAndGet();
                 catch (Exception e2) 
                    // biz exception
                 finally 
                    total.incrementAndGet();
                    if (entry != null) 
                        entry.exit();
                    
                
                Random random2 = new Random();
                try 
                    TimeUnit.MILLISECONDS.sleep(random2.nextInt(50));
                 catch (InterruptedException e) 
                    // ignore
                
            
        
    

    static class TimerTask implements Runnable 

        @Override
        public void run() 
            long start = System.currentTimeMillis();
            System.out.println("begin to statistic!!!");
            long oldTotal = 0;
            long oldPass = 0;
            long oldBlock = 0;
            while (!stop) 
                try 
                    TimeUnit.SECONDS.sleep(1);
                 catch (InterruptedException e) 
                

                long globalTotal = total.get();
                long oneSecondTotal = globalTotal - oldTotal;
                oldTotal = globalTotal;

                long globalPass = pass.get();
                long oneSecondPass = globalPass - oldPass;
                oldPass = globalPass;

                long globalBlock = block.get();
                long oneSecondBlock = globalBlock - oldBlock;
                oldBlock = globalBlock;

                System.out.println(TimeUtil.currentTimeMillis() + ", total:" + oneSecondTotal
                        + ", pass:" + oneSecondPass
                        + ", block:" + oneSecondBlock);
                if (seconds-- <= 0) 
                    stop = true;
                
            

            long cost = System.currentTimeMillis() - start;
            System.out.println("time cost: " + cost + " ms");
            System.out.println("total:" + total.get() + ", pass:" + pass.get()
                    + ", block:" + block.get());
            System.exit(0);
        
    


创建UserEntity

代码如下(示例):

package com.example.springcloudalibabasentineldemo.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;

/**
 * @className: RedisController
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
@Data
@TableName("t_user")
public class UserEntity implements Serializable 
	private static final long serialVersionUID = 1L;

	/**
	 * 
	 */
	@TableId
	private Integer id;
	/**
	 * 
	 */
	private String username;
	/**
	 * 
	 */
	private Integer age;



创建RRException

代码如下(示例):

/**
 * Copyright (c) 2016-2019 人人开源 All rights reserved.
 *
 * https://www.renren.io
 *
 * 版权所有,侵权必究!
 */

package com.example.springcloudalibabasentineldemo.exception;


/**
 * @description:自定义异常
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class RRException extends RuntimeException 
	private static final long serialVersionUID = 1L;
	
    private String msg;
    private int code = 500;
    
    public RRException(String msg) 
		super(msg);
		this.msg = msg;
	
	
	public RRException(String msg, Throwable e) 
		super(msg, e);
		this.msg = msg;
	
	
	public RRException(String msg, int code) 
		super(msg);
		this.msg = msg;
		this.code = code;
	
	
	public RRException(String msg, int code, Throwable e) 
		super(msg, e);
		this.msg = msg;
		this.code = code;
	

	public String getMsg() 
		return msg;
	

	public void setMsg(String msg) 
		this.msg = msg;
	

以上是关于Spring Cloud Alibaba Sentinel集成的主要内容,如果未能解决你的问题,请参考以下文章

Spring Cloud Alibaba环境搭建

Spring Cloud Alibaba全家桶——Spring Cloud Alibaba介绍

Spring Cloud Alibaba系列教程——Spring Cloud Alibaba开篇

spring boot 整合spring cloud alibaba

spring boot 整合spring cloud alibaba

深度剖析Spring Cloud Alibaba系列——如何兼容Spring Cloud