Spring Cloud Alibaba微服务组件学习笔记

文章目录

  • 一、版本说明
    • 版本关系
    • 项目创建
  • 二、Nacos注册中心
    • 什么是Nacos
    • Nacos注册中心
    • 核心功能
    • Nacos Server部署(windows版本)
    • Nacos Client服务
    • Nacos Server配置项详解:
    • Nacos集群搭建:
  • 三、Ribbon负载均衡
    • 主流的负载方案:
    • 常见的负载均衡算法,实现接口 `IRule`:
    • Nacos使用Ribobn
    • 自定义负载算法:
    • 自定义配置文件修改负载策略:
    • Ribbon饥饿加载:
    • Load Balancer替换Ribbon
  • 四、微服务调用组件Feign
    • 使用OpenFeign
    • Feign的自定义配置
      • 日志配置
      • 契约配置
      • 超时时间配置
      • 自定义拦截器实现认证
  • 五、Nacos配置中心
    • 新增Nacos Config配置文件
    • 搭建Nacos Config的服务读取配置文件
  • 六、Sentinel分布式高可用组件
    • 快速开始:
    • @SentinelResource的使用
    • 流量控制规则 ==*FlowRule*==,服务提供端使用
    • 熔断降级规则 ==*DegradeRule*==,服务消费端使用
    • Sentinel控制台
    • Spring Cloud Alibaba整合Sentinel:
  • 七、分布式事务Seata


一、版本说明

  1. 版本关系

    github查看:https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E

    在这里插入图片描述

    在这里插入图片描述

    链接包含了项目所需依赖,只需在 <dependencyManagement> 中添加 Spring Cloud Alibaba 依赖即可:

    <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2.2.7.RELEASE</version><type>pom</type><scope>import</scope>
    </dependency>
    

    父项目添加依赖后,子项目自动继承依赖。

  2. 项目创建

    • 阿里云脚手架:https://start.aliyun.com/
    • Spring脚手架:https://start.spring.io/

二、Nacos注册中心

  1. 什么是Nacos

    集:注册中心配置中心服务管理 的平台。

    关键特性:

    • 服务发现和服务健康监测
    • 动态配置服务
    • 动态 DNS 服务
    • 服务及其元数据 (服务名称、地址、命名空间等) 管理
  2. Nacos注册中心

    引入心跳机制,定时接收心跳信息,若没有按时接收到心跳 (默认5秒发送一次) ,则注册中心便会将status改为down;若15秒内还没有心跳,则不会再拉取该服务,同时服务健康状态变为false;再后达到一定时间 (默认30秒) 没有心跳,则直接剔除该服务。
    在这里插入图片描述

  3. 核心功能

    Nacos Discovery

    • 服务注册:Nacos Client发送REST请求向Nacos Server注册服务;
    • 服务心跳:注册后,会维护一个定时心跳,默认5秒一次;
    • 服务同步:Nacos Server集群之间会互相同步服务实例;
    • 服务发现:Nacos Client在调用服务时,会缓存Server中的服务清单到本地,并启动一个定时任务定时拉取最新服务清单来更新本地缓存;
    • 服务监控检查:Nacos Server会开启一个定时任务检查注册服务的健康状态,15s未接收到心跳,健康状态将视为false,服务发现不会拉取;30s没有心跳,则直接剔除该服务实例。
  4. Nacos Server部署(windows版本)

    Nacos服务端下载 :https://github.com/alibaba/nacos/releases/;自行选择合适的版本下载,源码等。

    Nacos帮助文档 :https://nacos.io/zh-cn/docs/what-is-nacos.html/

    • 配置启动方式为单机模式 (默认为集群方式):
      • 编辑 nacos/bin/startup.cmd 文件,将 set MODE="cluster" 修改为 set MODE="standalone" 模式;
      • 配置Nacos服务,nacos/conf/application.properties 修改端口号、超时时间、最大连接数、数据源 等信息,默认存储位置是内存中,集群启动一般设置为MYSQL中;
      • 登录账户密码默认都是nacos;
    • 注意:Nacos2.0.3版本对 JDK 的要求,如果启动失败,先更新 JDK 版本!此处使用的是1.8.0_311
  5. Nacos Client服务

    1. 引入Nacos服务发现的依赖,版本由父工程提供:

      <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
      </dependency>
      
    2. yml配置:

      # 应用服务 WEB 访问端口
      server:port: 8080
      # 应用名称
      spring:application:name: order-service   # 注册 Nacos Server将采用应用名称cloud:nacos:server-addr: 127.0.0.1:8848 # 注册地址discovery:username: nacos   # Nacos Server登录账户、密码、命名空间(自定义 dev / product)password: nacosnamespace: publicephemeral: false	# 默认true,切换临时/永久,永久实例宕机后注册中心不会删除服务
      
    3. 如果使用 RestTemplate 模板类调用接口,需要配置如下:

      @Configuration
      public class RestTemplateConfig {@Bean@LoadBalanced		//此处一定要配置负载均衡注解,Nacos不知道调用哪个服务public RestTemplate getRestTemplate(RestTemplateBuilder builder) {RestTemplate restTemplate = builder.build();return restTemplate;}
      }
      
    4. 启动类注解:@EnableDiscoveryClient,可加可不加,高版本的SpringCloud做了处理;

    5. 代码参考

      • order-service代码,服务调用者:
      @RestController
      @RequestMapping("/order")
      public class OrderController {@Autowiredprivate RestTemplate restTemplate;@RequestMapping("/getOrder")public String getOrder(){String info =restTemplate.getForObject("http://stock-service/stock/getStock", String.class);return "HELLO WORLD!" + info;}
      }
      
      • stock-service代码,服务提供者,此处复制启动类端口8082测试负载均衡,默认轮询:
      @RestController
      @RequestMapping("/stock")
      public class StockController {@Value("${server.port}")private String port;@RequestMapping("/getStock")public String getStock(){return "下单了!" + port;}
      }
      
  6. Nacos Server配置项详解:

    • 命名空间:namespace,可创建多个命名空间,区分不同的项目或项目组等;

      在这里插入图片描述

    • 服务管理

      在这里插入图片描述

      (1) 服务列表:

      • 保护阈值:取值范围0~1,0表示不开启;当 健康实例 / 总实例数 < 阈值 时,服务会将不健康的服务拿去使用,防止雪崩;

      • 临时实例:ephemeral,默认true,切换临时/永久,永久实例宕机后注册中心不会删除服务,结合保护阈值使用;

      • 权重:weight,结合负载均衡策略使用,越大则调用的次数越多;

      • 分组:group,默认值“DEFAULT_GROUP”,比命名空间更细致的划分;

      • 元数据:metadata,键值对类型的值,用于扩展功能;

        在这里插入图片描述

      (2) 订阅者列表:

      ​ 用于查询哪个服务被调用,调用者名称等信息;

    • 权限管理:配置登录Nacos的账户、密码、访问权限等信息;

    • 配置管理:统一配置服务的配置项,类似Spring Cloud Config的功能;

    • 集群管理:Nacos集群的配置;

  7. Nacos集群搭建:

    环境:JDK1.8+,Maven3.3+,Nginx,MYSQL5.7+;

    参考文档:https://nacos.io/zh-cn/docs/cluster-mode-quick-start.html

    1. 复制三个节点,分别安装Nacos,搭建伪集群测试;

    2. 修改配置文件 application.propprties,配置数据源,MYSQL5.7+;

    3. 修改配置文件cluster.conf.example,改为cluster.conf,内部配置集群的 IP 地址:

      # ip:port
      192.168.2.100:8849
      192.168.2.101:8850
      192.168.2.102:8851 
      
    4. 数据库运行Nacos的sql脚本,创建数据库;

    5. 修改启动脚本 startup.sh:

    • 启动方式为集群:set MODE="cluster"
    • 内存不足时 (此处虚拟机内存较小) ,修改小一些: JAVA_OPT="${JAVA_OPT} -server -Xms512m -Xmx512m -Xmn256m -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=128m"
    1. 官方推荐,nginx作为反向代理:

      • 配置 nginx.conf 配置文件:

        upstream nacoscluster { server 192.168.2.100:8849;server 192.168.2.101:8850;server 192.168.2.102:8851;
        }	
        server { listen 8848;server_name localhost;location /nacos/ {# 反向代理的路径,如访问http://192.168.2.100:8848将均衡代理到对应的Nacos上proxy_pass http://nacoscluster/naocs/;}
        }
        

三、Ribbon负载均衡

Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡工具,它通过Load Balance获取到服务端的所有机器实例,基于某种规则去调用这些服务,同时也可以实现我们自己的负载均衡算法。

  1. 主流的负载方案:

    • 集中式负载均衡 (服务端),硬件 / 软件的方式,如Nginx;
    • 客户端负载均衡,根据自身请求的状况做负载均衡;
  2. 常见的负载均衡算法,实现接口 IRule

    在这里插入图片描述

    • 随机

    • 轮询

    • 加权轮询

    • 地址Hash算法

    • 最小连接数

      ……

  3. Nacos使用Ribobn

    1. 依赖问题;nacos-discovery 中添加了Ribbon的依赖,所以无需在添加!
    2. 添加注解:@LoadBalanced 加在RestTemplate配置类中;
    3. RestTemplate调用的 url 地址,将 IP 改为对应的服务名称;
  4. 自定义负载算法:

    1. 自定义配置类,可自己实现AbstractLoadBalancerRule抽象类,重写choose方法,使用getLoadBalancer方法获取所有的服务,按需返回指定的服务,即可实现自己需要的负载策略:

      @Bean
      public IRule getIRule() {return new NacosRule();
      }
      

      注意此处的配置类不能放在启动类可扫描到的包下,否则会被所有服务共享策略!!!

    2. 启动类配置注解,针对某一服务进行负载均衡策略:

      @SpringBootApplication
      @RibbonClients(value = {@RibbonClient(name = "order-service", configuration = RestTemplateConfig.class),@RibbonClient(name = "stock-service", configuration = RestTemplateConfig.class)
      })
      public class OrderNacosApplication {public static void main(String[] args) {SpringApplication.run(OrderNacosApplication.class, args);}}
      
  5. 自定义配置文件修改负载策略:

    采用NacosRule,它实现了Nacos的权重,可以在Nacos中配置,也可以在配置文件中配置weight,设置为0表示不使用此服务。

    # 基于配置文件形式的 针对单个服务的 Ribbon 负载均衡策略
    stock-service:  # 被调用者的服务名称ribbon:NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
    
  6. Ribbon饥饿加载:

    默认关闭,开启后,服务将在启动时初始化负载策略,解决服务初次访问速度响应慢的问题;

    ribbon:eager-load:enabled: true	# 开启饥饿加载# 指定需要饥饿加载的服务名称,多个服务使用逗号分隔clients: stock-service, order-service
    
  7. Load Balancer替换Ribbon

    支持RestTemplate、WebClient两种方式;

    1. 添加SpringCloud父依赖:

      <!--父工程添加如下依赖-->
      <dependencyManagement><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency>
      </dependencyManagement>
      
    2. nacos-discovery依赖,排除掉Ribbon,子项目添加Load Balancer依赖:

      <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId><exclusions><exclusion><!--排除Ribbon依赖--><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-ribbon</artifactId></exclusion></exclusions>
      </dependency>
      <!--添加loadbalancer依赖-->
      <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId>
      </dependency>
      
    3. yml文件禁用Ribbon功能:

      spring:cloud:loadbalancer:ribbon:enabled: false
      
    4. 启动类配置,类似 @RibbonClients 的用法:

      @LoadBalancerClients(value = {@LoadBalancerClient(name = "order-service", configuration = RestTemplateConfig.class),@LoadBalancerClient(name = "stock-service", configuration = RestTemplateConfig.class)
      })
      
    5. 自定义负载策略,实现 ReactorLoadBalancer 接口,重写choose方法,实现自己的负载策略。


四、微服务调用组件Feign

Feign 是Netflix开发的声明式、模板化的HTTP客户端。可以更发方便简洁的调用HTTP API。

SpringCloud Openfeign 对Feign 进行了增强,使其支持SpringMVC注解,而且还整合了Ribbon和Nacos。

  1. 使用OpenFeign

    1. 添加父依赖:spring-cloud-dependencies

    2. 添加openfeign依赖:

      <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
      </dependency>
      
    3. 服务调用者编写Feign接口,这里需要保证服务提供者服务存在Nacos中:

      /*** name:需要调用的服务名称* path:也可以去掉,去使用@RequestMapping("/stock")*/
      @FeignClient(name = "stock-service", path = "/stock")
      public interface StockFeignService {@RequestMapping("/getStock")String getStock();
      }
      
    4. 启动类开启Feign功能:@EnableFeignClients,添加在启动类或配置类上;

  2. Feign的自定义配置

    1. 日志配置

      • 自定义配置类,配置日志级别:

        @Configuration
        public class FeignConfig {@Beanpublic Logger.Level feignLoggerLevel() {return Logger.Level.FULL;	// 选择一种配置// return Logger.Level.BASIC;// return Logger.Level.HEADERS;// return Logger.Level.NONE;}
        }
        
      • yml配置文件修改Spring默认日志级别,改为只打印Feign的日志:

        # Spring的日志级别是info,而feign的日志级别是debug,不改这里就不会输出feign日志
        logging:level:# 只输出指定的Feign接口日志信息com.axin.feign.StockFeignService: debug
        
      • 局部日志配置

        • 第一种,将配置类的 @Configuration 去除,而在 @FeignClient 注解上配置属性:

          @FeignClient(name = "stock-service", configuration = FeignConfig.class)
          public interface StockFeignService {@RequestMapping("/getStock")String getStock();
          }
          
        • 第二种,修改yml配置文件:

          feign:client:config:stock-service:  # 日志的服务名称loggerLevel: BASIC
          
    2. 契约配置

      原生Feign是不支持SpringMVC注解的,所以修改契约配置可以去使用原生的Feign注解,如老项目升级。

      修改配置后,Feign接口将不能使用MVC注解,而是使用原生注解。

      • 配置类修改契约配置:

        @Bean
        public Contract feignContract() {return new Contract.Default();
        }
        
      • 配置文件yml修改:

        feign:client:config:stock-service:  # 服务名称contract: feign.Contract.Default  # 契约配置,还原原生注解
        
      • 原生注解对应MVC注解:

        @RequestMapping("/getStock") ==> @RequestLine("GET /getStock") 手动配置请求方法;

        @PathVariable ==> @Param

    3. 超时时间配置

      • 全局配置类配置:

        @Bean
        public Request.Options options() {return new Request.Options(5000, 10000);
        }
        
      • 配置文件yml配置:

        feign:client:config:stock-service:  # 服务名称connectTimeout: 5000    # 连接超时的时间,默认2sreadTimeout: 10000      # 响应超时的时间,默认5s
        
    4. 自定义拦截器实现认证

      • 配置类配置,自定义拦截器,实现RequestInterceptor接口,重写apply方法,加入Spring容器内;

      • 配置文件yml配置,这里拦截器就无需加入Spring容器了:

        feign:client:config:stock-service:  # 服务名称requestInterceptors[0]: # 配置拦截器com.it.config.FeignAuthRequestInterceptor   # 自定义拦截器全路径
        

五、Nacos配置中心

  1. 新增Nacos Config配置文件

    1. Nacos服务端新增配置:

      注:微服务将自动读取Nacos中与微服务名称一样的配置文件名!!!

      在这里插入图片描述

    2. 启用Nacos的权限控制,nacos/conf/application.properties 中修改配置文件:

      权限控制开启后,微服务中必须配置Nacos的用户名和密码,否则报错!!!

      ### If turn on auth system:
      nacos.core.auth.enabled=true	# 默认false
      
  2. 搭建Nacos Config的服务读取配置文件

    1. 添加依赖:

      <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
      </dependency>
      
    2. 配置bootstrap.yml文件,此处没有开启权限控制,无需配置Nacos的用户名和密码:

      spring:application:name: config-servicecloud:nacos:server-addr: 127.0.0.1:8848
      
    3. 测试读取配置信息:

      @SpringBootApplication
      public class ConfigNacosApplication {public static void main(String[] args) {ConfigurableApplicationContext applicationContext = SpringApplication.run(ConfigNacosApplication.class, args);ConfigurableEnvironment environment = applicationContext.getEnvironment();System.out.println("my.name:" + environment.getProperty("my.name"));System.out.println("my.password:" + environment.getProperty("my.password"));}}
      

      在这里插入图片描述

    4. 测试实时修改Naocs配置中心的配置,微服务将自动拉取新的信息;

    5. 修改微服务配置的文件格式,默认的格式为properties

      spring:cloud:nacos:config:file-extension: yaml
      
    6. 配置profiles

      • Nacos配置中心的配置

        dataid的命名:服务名 - 环境 - 文件后缀,如config-nacos-dev.yml;

        注意:默认的配置文件(与服务名相同的dataid的配置文件),则无需添加文件后缀。

      • 本地微服务的配置

        application.yml中,使用 spring.profiles.active 选择 dev / product 环境。

      • 配置文件的优先级

        profiles > 默认 > 自定义dataid配置,优先级大的将覆盖小的,同时配置将互补,配置一项即可。

    7. 配置命名空间namespace,微服务配置后,将读取指定命名空间中的配置信息。

    8. 配置组group,微服务配置后,将读取指定组内的配置信息。

    9. 自定义dataid配置文件的读取:

      共两种方式,二者功能一致,只是优先级不同。

      extension-configs > shared-configs,同时,数组的下标越大优先级越大。

      • shared-configs数组:

        注意:SpringBoot 将优先使用最后读取的配置文件,此处将选择下标1的配置。

        spring:cloud:nacos:server-addr: 127.0.0.1:8848config:file-extension: yamlshared-configs:   # 接收一个数组- data-id: my.config1.yml	# 下标为0refresh: true- data-id: my.config2.yml	# 下标为1,SpringBoot优先使用后读取的配置refresh: true
        
      • extension-configs数组:

        spring:cloud:nacos:server-addr: 127.0.0.1:8848config:file-extension: yamlextension-configs:   # 接收一个数组- data-id: my.config3.yml   # 下标为0refresh: true- data-id: my.config4.yml   # 下标为1refresh: true
        
    10. java类中动态获取配置信息:

      注意:正常情况下,修改配置中心的配置后,类中是无法动态取到的,需要添加注解 @RefreshScope

      @RefreshScope
      @RestController
      @RequestMapping("/config")
      public class ConfigController {@Value("${my.name}")private String name;@Value("${my.password}")private String password;@RequestMapping("/show")public String show(){return this.toString();}@Overridepublic String toString() {return "ConfigController{" +"name='" + name + '\'' +", password='" + password + '\'' +'}';}
      }
      

六、Sentinel分布式高可用组件

  1. 说明文档:https://github.com/alibaba/Sentinel

Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来保障微服务的稳定性。

Sentinel的特征:

  • 丰富的应用场景:
  • 完备的实时监控:
  • 广泛的开源生态:
  • 完善的SPI扩展点:

Sentinelhystrix对比:

在这里插入图片描述

  1. 快速开始:

    1. 核心依赖:

      <dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-core</artifactId><version>1.8.4</version>
      </dependency>
      
    2. 其他依赖:

      <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      
    3. 自定义一个Controller:

      import com.alibaba.csp.sentinel.Entry;
      import com.alibaba.csp.sentinel.SphU;
      import com.alibaba.csp.sentinel.slots.block.BlockException;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;@RestController
      public class HelloWorldController {@RequestMapping("/hello")public String helloWorld() {Entry entry = null;try {entry = SphU.entry("hello");return "hello world";}catch (BlockException be) {return "限流了";} catch (Exception e) {e.printStackTrace();return "error";} finally {if (entry != null) {entry.exit();}}}}
      
    4. 自定义一个Spring的初始化方法,内部添加限流规则:

      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 org.springframework.context.annotation.Configuration;import javax.annotation.PostConstruct;
      import java.util.ArrayList;@Configuration
      public class SpringInitConfig {@PostConstruct  // 初始化方法, 类加载的时候执行, 在这里添加限流规则, 也可在启动类中添加private static void initFlowRule() {ArrayList<FlowRule> flowRules = new ArrayList<>();FlowRule rule = new FlowRule(); // 创建限流规则rule.setResource("hello");  //资源名称,可以是类名、方法名、路径名等rule.setGrade(RuleConstant.FLOW_GRADE_QPS); //限流等级rule.setCount(1);   // 限流阈值, 即每秒钟最多访问1次, 参数类型为doubleflowRules.add(rule);// 注册限流规则FlowRuleManager.loadRules(flowRules);   // 加载限流规则}
      }
      
    5. 端口号配置:

      server:port: 8080
      
    6. 启动项目,浏览器访问:http://localhost:8080/hello

    7. 缺点:代码复杂,嵌入代码过多

  2. @SentinelResource的使用

    1. 文档:https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81

    2. 添加依赖

      <dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-annotation-aspectj</artifactId><version>1.8.4</version>
      
    ```
    1. 配置SentinelResourceAspect切面类,加入到Spring容器中:

      /*** 配置SentinelResourceAspect, 会自动拦截@SentinelResource注解的方法*/
      @Bean
      public SentinelResourceAspect sentinelResourceAspect() {return new SentinelResourceAspect();
      }
      
    2. 处理器方法上添加注解==@SentinelResource==:

      @SentinelResource(value = "user",blockHandler = "userBlockHandler",fallback = "userFallback",exceptionsToIgnore = {NullPointerException.class}
      )
      @RequestMapping("/user")
      public User getUser(@RequestParam(required = false, value = "num") String num) {if (num != null) {throw new RuntimeException("降级了");} return new User("张三", "23");
      }public User userBlockHandler(String num, BlockException e) {e.printStackTrace();return new User("限流了", "0");
      }public User userFallback(String num, Throwable e) {e.printStackTrace();return new User("降级了", "0");
      }
      
    3. 在Spring的初始化方法中,内部添加限流规则:

      @PostConstruct  // 初始化方法, 在类加载的时候执行
      private static void initFlowRule() {ArrayList<FlowRule> flowRules = new ArrayList<>();FlowRule rule2 = new FlowRule(); // 创建限流规则(流量的控制), 可以添加多个rule2.setResource("user");  //资源名称,可以是类名、方法名、路径名等,具体参考官方文档rule2.setGrade(RuleConstant.FLOW_GRADE_QPS);rule2.setCount(1);   // 限流阈值, 即每秒钟最多访问1次, 参数类型为doubleflowRules.add(rule2);// 注册限流规则FlowRuleManager.loadRules(flowRules);   // 加载限流规则
      }
      
    4. @SentinelResource的常用属性

      • value:资源名称,可以是类名、方法名、路径名等

      • blockHandler:限流时执行的方法,返回值类型与原返回值类型一致,参数可以新增BlockException

      • blockHandlerClass:限流时执行方法存在的类,使用blockHandler指定对应的方法,需要使用static修饰

      • fallback:降级处理器,用于接收异常,当资源被降级时,会调用该处理器,返回值类型与原返回值类型一致,参数可以新增Throwable

      • fallbackClass:降级时执行方法存在的类,使用fallback指定对应的方法,需要使用static修饰

      • exceptionsToIgnore:排除的异常,如果抛出的异常在exceptionsToIgnore中,则不会被限流

      • 注意blockHandlerfallback 同时使用时,blockHandler的优先级更高

      • 注意2:自定义blockHandler 方法时,一定要记得添加对应的异常参数,否则无法生效;

  3. 流量控制规则 FlowRule,服务提供端使用

    @PostConstruct
    private static void initFlowRule() {ArrayList<FlowRule> rules = new ArrayList<>();FlowRule rule = new FlowRule(); // 创建限流规则rule.setResource("hello");  //资源名称rule.setGrade(RuleConstant.FLOW_GRADE_QPS); //限流等级,分为:QPS(每秒请求数)、线程数rule.setCount(1);   // 限流阈值, 即每秒钟最多访问次数, 参数类型为doublerules.add(rule);// 注册限流规则FlowRuleManager.loadRules(rules);   // 加载限流规则
    }
    
  4. 熔断降级规则 DegradeRule,服务消费端使用

    @PostConstruct
    private static void initDegradeRule() {ArrayList<DegradeRule> rules = new ArrayList<>();DegradeRule rule = new DegradeRule();   // 降级规则rule.setResource("degrade");  //资源名称/** 60秒内,请求次数超过2次,出现2个异常,则降级,调用降级的方法,降级时间为10秒* 降级之后会处于"半开"状态:当10秒之后,若再次调用发生一次异常,则将立即触发降级*/rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);  //降级等级:慢调用比例、异常比例、异常数rule.setCount(2);   // 异常数超过2次,则降级rule.setMinRequestAmount(2); // 触发熔断的最小请求数,参数类型为intrule.setStatIntervalMs(60 * 1000); // 统计时长,单位为毫秒,默认1000msrule.setTimeWindow(10); // 触发熔断时长,单位为秒rules.add(rule);// 注册降级规则DegradeRuleManager.loadRules(rules);    // 加载降级规则
    }
    
  5. Sentinel控制台

    1. 版本:依据 Spring Cloud Alibaba 的版本选择,此处为2.3.7,所以下载1.8.1版本的控制台;

    2. 下载jar包:https://github.com/alibaba/Sentinel/releases

    3. cmd启动:java -jar sentinel-dashboard-1.8.1.jar

    4. 访问:默认端口8080,http://localhost:8080/#/login

    5. 登陆:账户密码都为 sentinel

    6. 启动配置修改:

      • 端口:-Dserver.port=8858

      • 账户:-Dsentinel.dashboard.auth.username=sentinel

      • 密码:-Dsentinel.dashboard.auth.password=123456

      • 日志:

        • -Dlogging.file=.\logs\sentinel-dashboard.log
        • -Dcsp.sentinel.log.dir=.\logs\sentinel-dashboard
      • 自定义批处理文件

        • 新建文本文档,输入如下命令,修改文件名称为:start.bat

          title sentinel-dashboardjava -Dlogging.file=.\logs\sentinel-dashboard.log -Dcsp.sentinel.log.dir=.\logs\sentinel-dashboard -Dserver.port=8858 -Dsentinel.dashboard.auth.username=demo -Dsentinel.dashboard.auth.password=demo -jar sentinel-dashboard-1.8.1.jarpause
          
        • 访问地址:http://localhost:8858/#/login

    7. Sentinel控制台与微服务建立通信

      1. 引入依赖:

        <dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-transport-simple-http</artifactId><version>1.8.4</version>
        </dependency>
        
      2. 参数配置:

        微服务启动时,配置Sentinel控制台的IP地址及端口号,首次访问接口会注册到控制台内:

        -Dcsp.sentinel.dashboard.server=consoleIp:port

        在这里插入图片描述

        在这里插入图片描述

  6. Spring Cloud Alibaba整合Sentinel:

    1. 添加依赖:

      <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
      </dependency>
      
    2. 配置yml参数:

      # 应用名称
      spring:application:name: sentinel-alibaba
      # sentinel控制台地址cloud:sentinel:transport:dashboard: 127.0.0.1:8858log:	dir: .\logs\sentinel-dashboard	# 设置日志存储位置
      
    3. 用户首次访问路径时,当前服务会自动注册进控制台中;

    4. 自定义限流规则,此时无需再使用@SentinelResource注解一一配置限流方法:

      1. 创建Result类,返回统一的返回值类型;

        public class Result<T> {private Integer code;private String message;private T data;public Result(Integer code, String message) {this.code = code;this.message = message;}public static <T> Result<T> error(Integer code, String message) {return new Result<T>(code, message);}// ……省略部分代码
        }
        
      2. 自定义类,实现 BlockExceptionHandler 接口,重写内部方法;

        @Slf4j
        @Component
        public class MyBlockException implements BlockExceptionHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {log.error("当前的异常资源路径为:" + e.getRule());Result<String> result = null;if (e instanceof FlowException) {result = Result.error(500, "限流了,请稍后再试");} else if (e instanceof DegradeException) {result = Result.error(500, "降级了,请稍后再试");} else if (e instanceof ParamFlowException) {result = Result.error(500, "热点参数限流了,请稍后再试");} else if (e instanceof SystemBlockException) {result = Result.error(500, "触发系统保护规则了,请稍后再试");} else if (e instanceof AuthorityException) {result = Result.error(500, "权限不足,授权规则不通过");}// 将结果转换为json格式response.setStatus(500);response.setCharacterEncoding("UTF-8");response.setContentType(MediaType.APPLICATION_JSON_VALUE);new ObjectMapper().writeValue(response.getWriter(), result);}
        }
        
      3. 测试的Controller:

        @RequestMapping("/myBlockExceptionTest")
        public User myBlockExceptionTest() {/** 访问每三次,抛出一个异常,否则返回User对象,* 测试自定义的限流类*/count++;if (count % 3 == 0) {throw new RuntimeException("自定义限流异常");}return new User("自定义的限流类", 23);
        }
        
      4. 在Seninel控制台配置限流规则;

        在这里插入图片描述

      5. 在Seninel控制台配置降级规则;

        在这里插入图片描述

      6. 注意:微服务每次重新启动时需要再次配置规则,后期可自行做Seninel控制台的持久化配置;

    5. 流控模式介绍:

      在这里插入图片描述

      • 直接:直接限制设置的资源路径,可以是路径名,也可以是方法;

      • 关联:当访问设置的资源路径时,对关联的路径进行限制,而不是设置的路径;

        • 新增方法:

          @RequestMapping("/add")		// 使用Jmeter访问此地址
          public User add() {return new User("add", 23);
          }@RequestMapping("/get")		// 使用浏览器访问此地址
          public User get() {return new User("get", 23);
          }
          
        • 新增流控规则:

          在这里插入图片描述

        • 使用Jmeter设置一个 线程组 ,增加 取样器HTTP请求 ,增加 监听器 结果树,如图:

          在这里插入图片描述

          在这里插入图片描述

        • 进入浏览器,访问 http://localhost:8123/get ,这时将会显示服务限流;

      • 链路

        对某一方法做限流时,使用链路,可以针对某一个入口方法(具体路径)做限流,在达到设置阈值时,进限流指定的入口方法,而不影响其他;

        • 创建Service及impl,新增流控的方法:

          @Service
          public class SentinelServiceImpl implements SentinelService {@Override@SentinelResource(value = "getUser", blockHandler = "handleException")public String getUser() {return "查询成功";}public String handleException(BlockException e) {return "查询失败";}
          }
          
        • Controller方法:

          @RequestMapping("/test1")
          public String test1() {return sentinelService.getUser() + "test1";
          }@RequestMapping("/test2")
          public String test2() {return sentinelService.getUser() + "test2";
          }
          
        • yml配置文件添加一项配置:

          spring:cloud:sentinel:web-context-unify: false  # 默认为true,将调用链路context收敛,无法使用链路流控,必须修改为false才能使用,
          
        • Sentinel控制台,任选一个getUser方法的簇点链路,配置流控:

          在这里插入图片描述

          在这里插入图片描述

    6. 流控效果介绍:

      在这里插入图片描述

      1. 快速失败:直接完成流控;
      2. Warm Up(激增流量):预热 / 冷启动,使流量在一定时间内,缓慢增加到阈值上限;
        • 冷加载因子:codeFactor,默认是3,即QPS从threshold/3开始,逐渐升至设定的QPS值。
      3. 排队等待(脉冲流量):不会立即流控,而是设置超时时间,让流控的请求在一定时间内去延迟执行,充分利用系统空闲时间;
    7. 熔断降级策略

      1. 慢调用比例:当服务执行时间超过设置的统计时长,称为一次慢调用。超过设定的比例开始降级;
      2. 异常比例:当服务出现的异常次数超过设定的比例开始降级;
      3. 异常数:当服务出现的异常次数超过设定的次数开始降级;
    8. 热点参数流控:针对REST风格,对访问频率高的参数值进行流控降级;

      在这里插入图片描述

      1. 参数索引:参数在方法中所在位置,从零开始计算;
      2. 参数类型:java参数,四类八种;
      3. 参数值:流控的参数具体值,可添加多个;
    9. 系统保护规则

      在这里插入图片描述

      1. LOAD自适应:仅对Linux等系统生效;
      2. 平均RT:当单台机器的入口流量的平均 RT 达到阈值,则自动触发系统保护规则;
      3. 并发线程数:当单台机器的并发线程数达到阈值,则自动触发系统保护规则;
      4. 入口QPS:当单台机器的入口流量的 QPS 达到阈值,则自动触发系统保护规则;
      5. CPU使用率:当CPU使用率超过阈值,则自动触发系统保护规则;
    10. openFeign整合Sentinel

      1. 依赖,nacos,feign,sentinel:

        <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        
      2. yml配置文件,开启feign对Sentinel的支持:

        feign:sentinel:enabled: true
        
      3. 自定义一个异常类,实现feign接口的所在的接口类,并加入Spring容器中;

      4. 在feign的接口类上,声明使用自己的异常类:

        @FeignClient(name = "stock-service", path = "/stock", fallback = FeignException.class)
        
    11. Sentinel规则的持久化(此处使用第三种模式:拉模式):

      在这里插入图片描述

      1. 添加三方的依赖:

        <dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        
      2. 在nacos中新增配置如下:

        [{"resource": "/getUser",	"controlBehavior": 0,"count": 2,"grade": 1,"limitApp": "default","strategy": 0,}
        ]
        
        • resource:流控的资源路径;
        • count:限流阈值;
        • grade:限流阈值类型,QPS为1,并发线程数为0;
        • limitApp:调用来源,默认default,不区分调用来源;
        • strategy:流控模式,直接、链路、关联;
        • controlBehavior:流控效果, 快速失败、Warm Up、排队等待;
        • clusterMode:是否集群限流
      3. 在application.yml配置文件中新增配置:

        详细配置参考 DataSourcePropertiesConfiguration 配置类

        spring:cloud:sentinel:datasource:   # 源码:DataSourcePropertiesConfiguration配置类flow-rule:    # 自定义的名称nacos:    # 可选值:nacos、zk、redis、apollo等等server-addr: localhost:8848   # nacos的ip地址username: nacos   # 用户名password: nacos   # 密码dataId: config-nacos-sentinel-flow-rule   # 配置中心自定义的配置的名称rule-type: flow   # 流控规则,具体查看RuleType枚举类
        

七、分布式事务Seata

  1. Seata官网:https://seata.apache.org/zh-cn/;

  2. 名词解释:

    • TMTransaction Manager,事务管理者。定义全局事务的范围,开始全局事务、提交或回滚;
    • RMResource Manager,资源管理者。管理分支事务处理的资源,与 TC 交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚;
    • TCTransaction Coordinator,事务协调者。维护全局和分支事务的状态,驱动全局事务提交或回滚;
  3. 四种事务模式:

    • XA模式:事务提交至事务协调者TC,由TC统一决定是否提交事务;

    • AT模式:事务直接提交,并记录 undo_log 日志(SQL执行前后各一条),异常后根据日志回滚;

    • TCC模式:自行决定事务的提交回滚策略,指定执行的方法;

    • Saga模式:长事务解决方案,一种分布式异步事务。分两种实现:

      • 状态机引擎:通过事件驱动的方法异步执行提高系统吞吐,可以实现服务编排需求;

      • 基于注解和拦截器:开发简单、学习成本低;

    模式一致性隔离性侵入性性能场景
    XA强一致完全隔离对一致性、隔离性有高要求的业务
    AT弱一致依赖全局锁隔离基于关系型数据库的大多数分布式事务场景
    TCC弱一致资源预留隔离prepare
    commit
    cancel
    需编写三个接口
    对性能要求较高的事务。
    有非关系型数据库要参与的事务
    Saga最终一致需编写状态机、
    补偿业务
    业务流程长、业务流程多,
    参与者包含其它公司遗留系统服务,
    无法提供 TCC 模式要求的三个接口
  4. 设计问题处理:

    • 脏写:事务回滚前,需校验数据库与记录日志是否相同,如果不同,说明出现了脏写,需人工处理;
    • 允许空回滚:Try拥堵或其它原因未执行,Cancel执行了;
    • 防悬挂控制:Cancel比Try先执行了,即允许空回滚,但要拒绝空回滚后的Try操作;
    • 幂等控制:Try、Commit、Cancel要保证幂等性,即一次请求和多次请求对系统资源的影响是一致的;
  5. 使用Seata(摘自官网):

    • 基本使用:在需要开启分布式事务的方法上添加注解 @GlobalTransactional 即可;

      @GlobalTransactional
      public void purchase(String userId, String commodityCode, int orderCount) {......
      }
      
    • Seata防止脏写:

      • 方法一:

        @GlobalTransactional
        @Transactional
        public boolean updateA(DTO dto) {serviceA.update(dto.getA());
        }
        
      • 方法二:

        @GlobalLock
        @Transactional
        public boolean updateA(DTO dto) {serviceA.selectForUpdate(dto.getA());serviceA.update(dto.getA());
        }
        

| XA | 强一致 | 完全隔离 | 无 | 差 | 对一致性、隔离性有高要求的业务 |
| AT | 弱一致 | 依赖全局锁隔离 | 无 | 好 | 基于关系型数据库的大多数分布式事务场景 |
| TCC | 弱一致 | 资源预留隔离 | prepare
commit
cancel
需编写三个接口 | 优 | 对性能要求较高的事务。
有非关系型数据库要参与的事务 |
| Saga | 最终一致 | 无 | 需编写状态机、
补偿业务 | 优 | 业务流程长、业务流程多,
参与者包含其它公司遗留系统服务,
无法提供 TCC 模式要求的三个接口 |

  1. 设计问题处理:

    • 脏写:事务回滚前,需校验数据库与记录日志是否相同,如果不同,说明出现了脏写,需人工处理;
    • 允许空回滚:Try拥堵或其它原因未执行,Cancel执行了;
    • 防悬挂控制:Cancel比Try先执行了,即允许空回滚,但要拒绝空回滚后的Try操作;
    • 幂等控制:Try、Commit、Cancel要保证幂等性,即一次请求和多次请求对系统资源的影响是一致的;
  2. 使用Seata(摘自官网):

    • 基本使用:在需要开启分布式事务的方法上添加注解 @GlobalTransactional 即可;

      @GlobalTransactional
      public void purchase(String userId, String commodityCode, int orderCount) {......
      }
      
    • Seata防止脏写:

      • 方法一:

        @GlobalTransactional
        @Transactional
        public boolean updateA(DTO dto) {serviceA.update(dto.getA());
        }
        
      • 方法二:

        @GlobalLock
        @Transactional
        public boolean updateA(DTO dto) {serviceA.selectForUpdate(dto.getA());serviceA.update(dto.getA());
        }
        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/401135.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spark MLlib 特征工程(上)

文章目录 Spark MLlib 特征工程(上)特征工程预处理 Encoding:StringIndexer特征构建:VectorAssembler特征选择:ChiSqSelector归一化:MinMaxScaler模型训练总结Spark MLlib 特征工程(上) 前面我们一起构建了一个简单的线性回归模型,来预测美国爱荷华州的房价。从模型效果来…

【C++语言】list的构造函数与迭代器

1. list的介绍及使用 1.1 list的介绍 list的文档介绍 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。 2. list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点…

C语言实现多种快速排序

目录 1.概念 2.快速排序hoare版本 2.1基本思想 2.2解释相遇处的值为何一定小于key 2.3hoare版本快速排序的实现 3.快速排序挖坑法 3.1基本思想 3.2挖坑法快速排序的实现 4. 快速排序前后指针版本 4.1基本思想 4.2快速排序前后指针版本实现 5.快速排序非递归版本 …

苹果笔记本电脑可以玩steam游戏吗 MacBook支持玩steam游戏吗 在Steam上玩黑神话悟空3A大作 苹果Mac怎么下载steam

游戏是生活的润滑剂&#xff0c;越来越多的用户开始关注Mac平台上可玩的游戏。幸运的是&#xff0c;Steam作为最大的数字发行平台之一&#xff0c;提供了大量适用于Mac操作系统的游戏。无论你是喜欢策略、冒险还是射击类游戏&#xff0c;都能在Steam上找到适合自己Mac设备玩耍的…

从0开始搭建vue + flask 旅游景点数据分析系统(九):旅游景点管理之增删改查

这一期来做旅游景点数据的增删改查 先看下我们做好的效果是这样的&#xff1a; ## 1 后台接口 这里的接口已经考虑到了分页的情况&#xff0c;因为前端的表格是带有分页的&#xff0c;接受的前端传过来的get参数为 title 、page、 limit &#xff0c;titie是查询的关键词&…

Matlab绘制像素风字母颜色及透明度随机变化动画

本文是使用 Matlab 绘制像素风字母颜色及透明度随机变化动画的教程 实现效果 实现代码 如果需要更改为其他字母组合&#xff0c;在下面代码的基础上简单修改就可以使用。 步骤&#xff1a;(1) 定义字母形状&#xff1b;(2) 给出字母组合顺序&#xff1b;(3) 重新运行程序&#…

iPhone 16 机模视频曝光,五种颜色各有千秋

科技博主的最新视频分享了苹果 iPhone 16 标准版的机模上手体验。 视频中展示了五种颜色的 iPhone 16&#xff1a;深邃的蓝色、柔和的粉色、纯净的白色、经典的黑色和生机勃勃的绿色。 与 iPhone 15 相比&#xff0c;iPhone 16 弃用了黄色&#xff0c;新增了白色&#xff0c;…

地质灾害评估和治理工程勘查设计资质乙级资质办理标准

地质灾害评估和治理工程勘查设计资质乙级资质的办理标准主要包括单位条件、专业技术人员条件、仪器设备要求以及申请材料等方面。以下是详细的办理标准&#xff1a; 一、单位条件 **1、法人资格&#xff1a;**申请单位应具有企业法人或者事业单位法人资格。 **2、管理体系&a…

奥运内容碎片化传播下,品牌营销开始要讲究“性价比”

8月12日凌晨&#xff0c;随着孙颖莎和其他代表各洲的运动员们一起熄灭了圣火&#xff0c;巴黎奥运会终于落下帷幕。 本届奥运会上&#xff0c;中国体育代表团表现出色&#xff0c;共获得40枚金牌&#xff0c;金牌总数位居全球榜首&#xff0c;创下了中国在境外奥运会上的最佳成…

人工智能领域颠覆性技术创新,数字人泛化AI时代来临

是先有鸡还是先有蛋&#xff0c;这个问题人类还没有搞清楚&#xff0c;这次又有一个新的问题产生了&#xff0c;是算法进化了AI&#xff0c;还是AI进化了算法。我们知道直播平台都是利用算法对数字人直播进行斟别&#xff0c;但这一次被数字人泛化技术颠覆了&#xff0c;AI回复…

报错解决——苹果电脑mac装windows10,总是提示“启动转换”安装失败:拷贝Windows安装文件时出错

报错原因&#xff1a; 所安装的镜像文件大于4GB。 解决办法一&#xff1a; 使用小于4GB的镜像文件。 参考文章&#xff1a; 安装小于4GB的windows系统镜像 小于4GB的windows10镜像下载&#xff1a; 系统库官网 解决办法二&#xff1a; 参考文章&#xff1a; Mac air装…

VS实用调试技巧(程序员的必备技能)

调试的重要性 在我们写代码的时候&#xff0c;如果程序出现了bug&#xff0c;那么下一步就是找到bug并修复bug!而这个找问题的过程就被称为调试&#xff08;英文叫debug&#xff0c;消灭bug的意思&#xff09;。 调试能观察到程序内部执行的细节&#xff0c;可以增加程序员对…

Kafka系列之:Kafka Connect深入探讨 - 错误处理和死信队列

Kafka系列之&#xff1a;Kafka Connect深入探讨 - 错误处理和死信队列 一、快速失败二、YOLO&#xff1a;默默忽略坏消息三、如果一条消息掉在树林里&#xff0c;会发出声音吗&#xff1f;四、将消息路由到死信队列五、记录消息失败原因&#xff1a;消息头六、记录消息失败原因…

什么是数据仓库ODS层?为什么需要ODS层?

在大数据时代&#xff0c;数据仓库的重要性不言而喻。它不仅是企业数据存储与管理的核心&#xff0c;更是数据分析与决策支持的重要基础。而在数据仓库的各个层次中&#xff0c;ODS层&#xff08;Operational Data Store&#xff0c;操作型数据存储&#xff09;作为关键一环&am…

【6大设计原则】代码的艺术:深入探索单一职责原则

1. 引言&#xff1a;理解软件设计的艺术 软件设计&#xff0c;如同艺术创作&#xff0c;需要遵循一定的原则和规则。设计模式六大原则&#xff0c;是软件设计中不可或缺的指导方针。它们为软件开发者提供了一种思考问题的方法&#xff0c;帮助我们编写出更加优雅、高效和可维护…

Rocky系统部署k8s1.28.2单节点集群(Containerd)+Kuboard

目录 Kubernetes介绍 Kubernetes具备的功能 Kubernetes集群角色 Master管理节点组件 Node工作节点组件 非必须的集群插件 Kubernetes集群类型 Kubernetes集群规划 集群前期环境准备 开启Bridge网桥过滤 关闭SWAP交换分区 安装Containerd软件包 K8s集群部署方式 集…

Type-C接口取电芯片-LDR6500

取电芯片&#xff0c;特别是针对Type-C接口的取电芯片&#xff0c;如LDR6328系列&#xff0c;是近年来电子设备领域的一个重要技术组件。这些芯片通过智能协议控制&#xff0c;实现高效、安全的充电过程&#xff0c;并广泛应用于智能手机、平板电脑、笔记本电脑、小家电等各类需…

骗水技巧!怎么让猫咪多喝水?热门补水猫罐头推荐

我家一开始喂的是猫粮&#xff0c;买的还是进口牌子。然后发现团团有很多眼屎&#xff0c;泪痕也很重&#xff0c;我一度怀疑是这个牌子的猫粮不太好&#xff0c;后来就换成了国产的&#xff0c;价格确实少了一半&#xff0c;但是问题还是没有改善&#xff0c;而且吃完以后&…

HarmonyOS应用二之代办事项案例

目录&#xff1a; 1、代码分析2、ArkTS的基本组成3、重点扩展 1、代码分析 1.1代码&#xff1a; 在鸿蒙&#xff08;‌HarmonyOS&#xff09;‌的ArkTS框架中&#xff0c;‌aboutToAppear() 是一个自定义组件的生命周期函数&#xff0c;‌它在组件即将显示时被系统自动调用1。…

多条折线图修改图例以及自定义tooltip

在图例后面添加所有数据之和修改之后 series 中的name之后导致tooltip也加上了重新自定义tooltip&#xff0c;去掉总量统计 核心代码 监听数据改变计算总量修改name字段自定义 tooltip // 计算每条线的总和 const sum1 this.VALUE1.reduce((acc, val) > acc val, 0); co…