当前位置: 首页 > news >正文

SpringCloud (1) 服务拆解

1 服务拆解和治理

1.1 服务拆解

        微服务的核心就是服务拆分,将传统的大项目拆分为多个微型服务(服务或微服务),实现服务之间"高内聚(微服务职责单一),低耦合(微服务功能相对独立)"的目的

                (1) 水平(横向)拆分:先搭出拆分框架,比如【公共服务】(比如:common服务,client服务...)可以作为一层,【业务微服务】可以作为一层

                (2) 垂直(竖向)拆分:在水平拆分的基础上,对某一层继续拆分

1.2 服务治理

        一旦服务做了拆分,各个服务之间就有了隔离,导致无法直接相互调用,而实现服务之间的相互调用就涉及到服务治理,服务治理包含3个角色:

        注册中心:记录并监控各个微服务实例状态(心跳机制),推送服务变更信息

        服务提供者:暴露服务接口,供其他微服务调用,当某个提供者有多个实例时,可以利用负载均衡算法,从多实例中选择一个实例提供服务

        服务消费者:调用其他微服务接口(提供者和消费者可以同时兼顾)

2 注册中心(Nacos)

        它是阿里巴巴的产品,目前已加入SpringCloudAlibaba中

        本文介绍的是基于Docker部署的Nacos

2.1 配置数据库(mysql)

        新建nacos数据库,nacos数据库中新建下表:

/** Copyright 1999-2018 Alibaba Group Holding Ltd.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*//******************************************/
/*   表名称 = config_info                  */
/******************************************/
CREATE TABLE `config_info` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',`data_id` varchar(255) NOT NULL COMMENT 'data_id',`group_id` varchar(128) DEFAULT NULL COMMENT 'group_id',`content` longtext NOT NULL COMMENT 'content',`md5` varchar(32) DEFAULT NULL COMMENT 'md5',`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',`src_user` text COMMENT 'source user',`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',`c_desc` varchar(256) DEFAULT NULL COMMENT 'configuration description',`c_use` varchar(64) DEFAULT NULL COMMENT 'configuration usage',`effect` varchar(64) DEFAULT NULL COMMENT '配置生效的描述',`type` varchar(64) DEFAULT NULL COMMENT '配置的类型',`c_schema` text COMMENT '配置的模式',`encrypted_data_key` varchar(1024) NOT NULL DEFAULT '' COMMENT '密钥',PRIMARY KEY (`id`),UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';/******************************************/
/*   表名称 = config_info_aggr             */
/******************************************/
CREATE TABLE `config_info_aggr` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',`data_id` varchar(255) NOT NULL COMMENT 'data_id',`group_id` varchar(128) NOT NULL COMMENT 'group_id',`datum_id` varchar(255) NOT NULL COMMENT 'datum_id',`content` longtext NOT NULL COMMENT '内容',`gmt_modified` datetime NOT NULL COMMENT '修改时间',`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',PRIMARY KEY (`id`),UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段';/******************************************/
/*   表名称 = config_info_beta             */
/******************************************/
CREATE TABLE `config_info_beta` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',`data_id` varchar(255) NOT NULL COMMENT 'data_id',`group_id` varchar(128) NOT NULL COMMENT 'group_id',`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',`content` longtext NOT NULL COMMENT 'content',`beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps',`md5` varchar(32) DEFAULT NULL COMMENT 'md5',`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',`src_user` text COMMENT 'source user',`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',`encrypted_data_key` varchar(1024) NOT NULL DEFAULT '' COMMENT '密钥',PRIMARY KEY (`id`),UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta';/******************************************/
/*   表名称 = config_info_tag              */
/******************************************/
CREATE TABLE `config_info_tag` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',`data_id` varchar(255) NOT NULL COMMENT 'data_id',`group_id` varchar(128) NOT NULL COMMENT 'group_id',`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',`tag_id` varchar(128) NOT NULL COMMENT 'tag_id',`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',`content` longtext NOT NULL COMMENT 'content',`md5` varchar(32) DEFAULT NULL COMMENT 'md5',`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',`src_user` text COMMENT 'source user',`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',PRIMARY KEY (`id`),UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag';/******************************************/
/*   表名称 = config_tags_relation         */
/******************************************/
CREATE TABLE `config_tags_relation` (`id` bigint(20) NOT NULL COMMENT 'id',`tag_name` varchar(128) NOT NULL COMMENT 'tag_name',`tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',`data_id` varchar(255) NOT NULL COMMENT 'data_id',`group_id` varchar(128) NOT NULL COMMENT 'group_id',`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',`nid` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'nid, 自增长标识',PRIMARY KEY (`nid`),UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation';/******************************************/
/*   表名称 = group_capacity               */
/******************************************/
CREATE TABLE `group_capacity` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',`group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群',`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数,,0表示使用默认值',`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',PRIMARY KEY (`id`),UNIQUE KEY `uk_group_id` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表';/******************************************/
/*   表名称 = his_config_info              */
/******************************************/
CREATE TABLE `his_config_info` (`id` bigint(20) unsigned NOT NULL COMMENT 'id',`nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'nid, 自增标识',`data_id` varchar(255) NOT NULL COMMENT 'data_id',`group_id` varchar(128) NOT NULL COMMENT 'group_id',`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',`content` longtext NOT NULL COMMENT 'content',`md5` varchar(32) DEFAULT NULL COMMENT 'md5',`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',`src_user` text COMMENT 'source user',`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',`op_type` char(10) DEFAULT NULL COMMENT 'operation type',`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',`encrypted_data_key` varchar(1024) NOT NULL DEFAULT '' COMMENT '密钥',PRIMARY KEY (`nid`),KEY `idx_gmt_create` (`gmt_create`),KEY `idx_gmt_modified` (`gmt_modified`),KEY `idx_did` (`data_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造';/******************************************/
/*   表名称 = tenant_capacity              */
/******************************************/
CREATE TABLE `tenant_capacity` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',`tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数',`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',PRIMARY KEY (`id`),UNIQUE KEY `uk_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表';CREATE TABLE `tenant_info` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',`kp` varchar(128) NOT NULL COMMENT 'kp',`tenant_id` varchar(128) default '' COMMENT 'tenant_id',`tenant_name` varchar(128) default '' COMMENT 'tenant_name',`tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',`create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',`gmt_create` bigint(20) NOT NULL COMMENT '创建时间',`gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',PRIMARY KEY (`id`),UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';CREATE TABLE `users` (`username` varchar(50) NOT NULL PRIMARY KEY COMMENT 'username',`password` varchar(500) NOT NULL COMMENT 'password',`enabled` boolean NOT NULL COMMENT 'enabled'
);CREATE TABLE `roles` (`username` varchar(50) NOT NULL COMMENT 'username',`role` varchar(50) NOT NULL COMMENT 'role',UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE
);CREATE TABLE `permissions` (`role` varchar(50) NOT NULL COMMENT 'role',`resource` varchar(128) NOT NULL COMMENT 'resource',`action` varchar(8) NOT NULL COMMENT 'action',UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
);

2.2 Docker中部署Nacos

2.2.1 拉取Nacos镜像

docker pull nacos/nacos-server

2.2.2 配置docker-compose.yml

services:nacos:  #如果是集群模式就用nacos1,nacos2,nacos3....    #云服务器内存最低选4G的image: nacos/nacos-servercontainer_name: nacos_containerrestart: always  #开机自启ports:- "8848:8848" #界面访问端口- "9848:9848" #程序使用grpc连接的端口- "9849:9849" #environment:MODE: standalone  #standalone表示单机模式,集群模式用clusterPREFER_HOST_MODE: hostname  #支持IP还是域名模式(默认ip),体现在访问地址时地址栏的显示(hostname显示会更简洁一点)#数据库用mysqlSPRING_DATASOURCE_PLATFORM: mysqlMYSQL_SERVICE_HOST: 123.123.123.123MYSQL_SERVICE_PORT: 3306MYSQL_SERVICE_DB_NAME: nacosMYSQL_SERVICE_USER: rootMYSQL_SERVICE_PASSWORD: 123456MYSQL_DB_PARAM: "characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai"  # 设置mysql的连接参数volumes:- "/root/docker_nacos/logs:/home/nacos/logs"networks:- sunner_network

2.2.3 生成nacos容器

        利用nacos镜像和docker-compose.yml生成nacos容器

docker compose up -d

3 服务注册

3.1 引入依赖

        父工程依赖管理:

<!--spring cloud-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>2022.0.4</version><type>pom</type><scope>import</scope>
</dependency><!--spring cloud alibaba(可以管理nacos注册,发现版本)-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2022.0.0.0</version><type>pom</type><scope>import</scope>
</dependency>

        子项目引入依赖:

<!--nacos"注册,发现"(被spring cloud alibaba管理版本)-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

3.2 配置application.yaml

spring:application:name: engineering  #微服务名称cloud:nacos:server-addr: 118.89.91.89:8848

3.3 访问nacos(8848端口)

        nacos是根据微服务名划分组别,因此即使多个同名的微服务部署在不同地址的服务器上,也会被nacos归为一组,当调用者调用此微服务时,nacos会根据负载均衡算法,从这组微服务中取出一个供调用者去调用

4 服务发现(OpenFeign)

        OpenFeign是一个声明式的http客户端,是SpringCloud在Eureka公司开源的Feign的基础上改造而来

4.1 调用微服务流程

        ①服务调用者去Nacos中获取某个微服务的分组列表

        ②微服务的分组列表中,利用"负载均衡"算法获取一个"包含HTTP的微服务请求地址"

        ③向获取的微服务发起http请求

4.2 引入依赖

<!--nacos"注册,发现"(被spring cloud alibaba管理版本)-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency><!--OpenFeign-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency><!--负载均衡(从获取的某微服务的列表中,利用负载均衡算法,选择其中一个微服务去调用)-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId> <!--早期用的是Ribbon-->
</dependency>

4.3 通过@EnableFeignClients注解,开启OpenFeign功能

/*** 启动SpringBoot项目的主入口程序*/
@MapperScan({"xyz.aboluo.cloud_test.dao"})  //dao接口包扫描
@EnableFeignClients("xyz.aboluo.cloud_test.client")  //配置包扫描,扫描不到的Client不生效,也无法通过@Autowired进行注入
@SpringBootApplication(scanBasePackages = "xyz.aboluo.cloud_test")  //标记这是一个SpringBoot应用
public class MainApplication {public static void main(String[] args) {ConfigurableApplicationContext iocContext = SpringApplication.run(MainApplication.class, args);
//            Teacher teacher = iocContext.getBean(Teacher.class);}
}

4.4 编写FeignClient

        注意事项:

                ①@FeignClient只会提供从nacos中获取的某个engineering实例的"IP地址+端口",不会提供"项目路径"

                ②需要明确注明@GetMapping或@PostMapping,不要使用@RequestMapping

                ③注解@PostMapping需要提供"项目路径+接口路径",拼接后就形成"IP地址+端口+项目路径+接口路径"

/*@FeignClient只会提供从nacos中获取的某个engineering实例的"IP地址+端口",不会提供"项目路径"*/
@FeignClient(value = "engineering")
public interface EngineeringClient {/*** 需要提供"项目路径+接口路径",拼接后就形成"IP地址+端口+项目路径+接口路径"* 需要明确使用@GetMapping@PostMapping,不要使用@RequestMapping*/@PostMapping("/engineering/alWindow/queryAlWindow.do")Result queryAlWindow(@RequestBody AlWindow alWindow);
}

4.5 使用FeignClient,实现远程调用

@RestController
@RequestMapping("/test")
public class EngineeringTestController {@Autowiredprivate EngineeringClient engineeringClient;@RequestMapping("/callEngineering.do")public Result queryAlWindow(@RequestBody AlWindow alWindow) {Result result = engineeringClient.queryAlWindow(alWindow);return Result.success(result);}
}

4.6 OpenFeign连接池

        OpenFeign最终发起远程调用是通过Client,而每次调用都需要重新创建Client对象进行连接,非常消耗资源,效率低,因此需要用到连接池(可以选择Apache HttpClient或OKHttp)

4.6.1 引入依赖

<!--ok-http连接池-->
<dependency><groupId>io.github.openfeign</groupId><artifactId>feign-okhttp</artifactId>
</dependency>

4.6.2 开启连接池功能

spring:application:name: cloud_test  #微服务名称cloud:nacos:server-addr: 123.123.123.123:8848openfeign:okhttp:enabled: true

5 服务拆解优化

        给所有需要提供微服务接口暴露(服务提供者)的方法上增加"支持Client"的注解,提醒开发者,如果此方法发生改变时,还需要去改变对应的Client

5.1 微服务拆解问题

        假设有3个微服务A、B、C,在B和C中都需要调用A,因此在B和C中都要写一个AClient供B或C的接口调用,并且要在B和C中添加Apojo

        此时就有2个问题:

                ①重复编写AClient和Apojo

                ②一旦A中的接口或pojo发生变化,B和C中的AClient或Apojo都需要做修改,导致微服务之间的耦合度高

5.2 拆解优化的2种思路

5.2.1 思路1(一拆三)

        单体项目拆分为多个服务a、b、c......,每个服务再拆分为3个服务:

                ①pojo服务:向其他微服务提供"对象关系映射(ORM)类"

                ②client服务:向其他微服务提供"调用本服务接口的Client"

                ③business服务:放置本服务的业务代码

        如果a是服务提供者,b、c是服务消费者,此时b和c就需要用到a中的pojo和client,此时只需要在b服务和c服务的pom.xml中引入a_pojo和a_client的依赖(此时b的子项目b_business和c的子项目c_business也同步引入了对应依赖)

        优点:①解决了重复编写pojo和client的问题 ②因为所有pojo和client都在a中进行维护,解决了高耦合问题

5.2.2 思路2(归总)

        新建一个client项目:

                ①将所有微服务的pojo都写在此项目的pojos文件夹下的对应文件夹里

                ②将所有微服务的Client都写在此项目的clients文件夹里

                ③微服务的pom.xml中引入client的依赖

                ④在"服务消费者"的启动类上加上@EnableFeignClients("xyz.aboluo.client.clients")

        水平拆分:

                水平A:公共模块作为一层

                水平B:业务模块作为一层

        垂直拆分:在水平拆分的基础上继续拆分

                公共模块:client模块,common模块.......

                业务模块:a模块、b模块、c模块......

相关文章:

SpringCloud (1) 服务拆解

1 服务拆解和治理 1.1 服务拆解 微服务的核心就是服务拆分,将传统的大项目拆分为多个微型服务(服务或微服务),实现服务之间"高内聚(微服务职责单一),低耦合(微服务功能相对独立)"的目的 (1) 水平(横向)拆分:先搭出拆分框架,比如【公共服务】(比如:common服务,client…...

STM32F407单片机编程入门(十) IWDG独立看门狗详解及实战含源码

文章目录 一.概要二.独立看门狗介绍1.独立看门狗基本介绍2.独立看门狗功能描述3.独立看门狗复位时间 三.CubeMX配置一个独立看门狗IWDG例程四.CubeMX工程源代码下载五.小结 一.概要 什么是单片机看门狗 看门狗&#xff08;WDT&#xff09;是一个定时器&#xff0c;开启看门狗定…...

solana项目counter,测试过程中执行报错记录分享

跟随HackQuest部署counter项目&#xff0c;使用 Solana 官方提供的 playgroud 。这个平台让我们的部署和测试过程变得更加简便高效。 合约代码 lib.rs中复制以下代码 use anchor_lang::prelude::*; use std::ops::DerefMut;declare_id!("CVQCRMyzWNr8MbNhzjbfPu9YVvr97…...

[Unity Demo]重启项目之从零开始制作空洞骑士Hollow Knight第一集:导入素材以及建立并远程连接git仓库

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、导入素材二、使用步骤 1.建立并远程连接git2.github和仓库连接总结 前言 好久没来CSDN看看&#xff0c;突然看到前两年自己写的文章从零开始制作空洞骑士只…...

单链表(c语言简单实现)

单链表是一种常见的数据结构 一、结构特点 1. 由一系列节点组成&#xff0c;每个节点包含数据域和指向下一个节点的指针域。 2. 最后一个节点的指针域为 null&#xff0c;表示链表的结尾。 二、主要操作 1. 插入节点&#xff1a;可以在链表的头部、尾部或特定位置插入新节点。…...

三菱变频器Modbus-RTU 通讯规格

能够从变频器的 RS-485 端子使用 Modbus-RTU 通讯协议&#xff0c;进行通讯运行和参数设定。 NOTE: 1、使用 Modbus-RTU 通讯协议时&#xff0c;请设定Pr.549 协议选择 “1” 2、从主机按地址0(站号0)进行hodbus-RTU通讯时&#xff0c;为广播通讯&#xff0c;变频器不向主机发…...

PyQt5库学习之QFileDialog.getOpenFileName函数

PyQt5库学习之QFileDialog.getOpenFileName函数 一、简介 QFileDialog.getOpenFileName 是 PyQt5 中的一个函数&#xff0c;它提供了一个标准的文件选择对话框&#xff0c;允许用户选择一个文件。这个函数是 QFileDialog 类的一部分&#xff0c;通常用于打开文件时让用户选择文…...

如何理解变量提升和函数提升

在 JavaScript 中&#xff0c;变量提升和函数提升是指在代码执行之前&#xff0c;变量和函数声明会被提升到其所在作用域的顶部。这意味着你可以在声明之前使用它们&#xff0c;但它们的行为有所不同。 变量提升 变量提升是指变量声明&#xff08;使用 var&#xff09;会被提…...

monorepo基础搭建教程(从0到1 pnpm+monorepo+vue)

monorepo 前言1、搭建空项目并配置pnpm-workspace.yamlpnpm initpnpm-workspace.yaml 2.配置packages测试文件配置相关内容 3.引入packages内容至公共package.json4.创建测试项目&#xff0c;并引入公共包结语 前言 有个项目要引入一个第三方库&#xff0c;但是第三方库下载下…...

使用Docker Compose一键部署

文章目录 使用Docker Compose一键部署一、引言二、环境准备1、安装Docker和Docker Compose1.1、安装Docker1.2、安装Docker Compose 2、验证安装 三、编写Docker Compose文件1、创建目录结构2、编写Dockerfile3、编写docker-compose.yml 四、部署项目1、构建镜像2、启动服务3、…...

【GVINS】

【GVINS】 1. GVINS的系统特点2. GVINS的融合导航存在问题3. GVINS的信号的组成4. GVINS的信号的组成 原理推导知乎 1. GVINS的系统特点 概述了一种名为GVINS的系统&#xff0c;它旨在解决视觉-惯性里程计&#xff08;VIO&#xff09;在长时间运行时出现的漂移问题。GVINS通过…...

Linux 给 vmlinux 添加符号

文章目录 前言一、centos7 给 vmlinux 添加符号二、ubuntu22.04 给 vmlinux 添加符号 前言 使用内核源码下的script文件&#xff1a;scripts/extract-vmlinux 可以从/boot/vmlinuz 提取出来 内核镜像文件vmlinux&#xff1a; # ./extract-vmlinux vmlinuz-3.10.0-693.el7.x86…...

【mac】MacOS无法打开XXX文件,因为无法验证开发者的问题解决

博主介绍&#xff1a; 大家好&#xff0c;我是想成为Super的Yuperman&#xff0c;互联网宇宙厂经验&#xff0c;17年医疗健康行业的码拉松奔跑者&#xff0c;曾担任技术专家、架构师、研发总监负责和主导多个应用架构。 技术范围&#xff1a; 目前专注java体系&#xff0c;以及…...

Docker 无法拉取雷池 WAF 的解决方法

引言&#xff1a; 近日&#xff0c;许多用户反映在使用 Docker 命令拉取雷池 WAF 镜像时遇到了困难&#xff0c;主要表现为连接超时错误。本文将为大家提供解决此问题的有效方法。 问题描述&#xff1a; 当尝试通过 Docker 命令拉取雷池 WAF 镜像时&#xff0c;部分用户遇到…...

进制转换,原码,反码,补码,二进制位运算及应用

进制转换 2B&#xff08;0--1)&#xff0c;8O(0--7)&#xff0c;10D&#xff0c;16H&#xff08;0——9,A——F&#xff09; 8位二进制数&#xff0c;左边高位&#xff0c;右边低位 2&#xff0c;8&#xff0c;16 -> 10进制整数&#xff0c;小数 整数&#xff1a;从后往…...

node.js居家养老服务系统—计算机毕业设计源码35247

目 录 摘要 1 绪论 1.1选题的背景 1.2研究的意义 1.3国内外居家养老信息化管理现状分析 1.4 express框架介绍 1.5node.js功能模块 1.6论文结构与章节安排 2 居家养老服务系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1数据增加流程 2.2.2数据修改流程 2.2.…...

OpenHarmony(鸿蒙南向开发)——小型系统芯片移植指南(二)

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ OpenHarmony&#xff08;鸿蒙南向开发&#xff09;——轻量系统芯片移植指南(一) Op…...

Live800:从心出发,以情动人:构建深度客户服务文化

在当今这个竞争激烈的市场环境中&#xff0c;企业之间的较量已不仅仅局限于产品质量的比拼&#xff0c;更在于谁能提供更优质、更贴心的客户服务。在这个背景下&#xff0c;“从心出发&#xff0c;以情动人”成为了构建深度客户服务文化的核心理念&#xff0c;它要求企业不仅要…...

分布式事务一致性:本地消息表设计与实践

概念 本地消息表是一种常见的解决分布式事务问题的方法。其核心思想是将分布式事务拆分成本地事务来处理&#xff0c;通过消息队列来保证各个本地事务的最终一致性。 实现步骤 创建本地消息表&#xff1a;在数据库中创建一个本地消息表&#xff0c;用于存储待发送的消息以及消…...

深入浅出Docker

1. Docker引擎 Docker引擎是用来运行和管理容器的核心软件。通常人们会简单的将其指代为Docker或Docker平台。 基于开放容器计划&#xff08;OCI&#xff09;相关的标准要求&#xff0c;Docker引擎采用了模块化的设计原则&#xff0c;其组件是可替换的。 Docker引擎由如下主…...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...

C#中的CLR属性、依赖属性与附加属性

CLR属性的主要特征 封装性&#xff1a; 隐藏字段的实现细节 提供对字段的受控访问 访问控制&#xff1a; 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性&#xff1a; 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑&#xff1a; 可以…...

Redis:现代应用开发的高效内存数据存储利器

一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发&#xff0c;其初衷是为了满足他自己的一个项目需求&#xff0c;即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源&#xff0c;Redis凭借其简单易用、…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...

手机平板能效生态设计指令EU 2023/1670标准解读

手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读&#xff0c;综合法规核心要求、最新修正及企业合规要点&#xff1a; 一、法规背景与目标 生效与强制时间 发布于2023年8月31日&#xff08;OJ公报&…...

C++实现分布式网络通信框架RPC(2)——rpc发布端

有了上篇文章的项目的基本知识的了解&#xff0c;现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...

Python训练营-Day26-函数专题1:函数定义与参数

题目1&#xff1a;计算圆的面积 任务&#xff1a; 编写一个名为 calculate_circle_area 的函数&#xff0c;该函数接收圆的半径 radius 作为参数&#xff0c;并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求&#xff1a;函数接收一个位置参数 radi…...

算法—栈系列

一&#xff1a;删除字符串中的所有相邻重复项 class Solution { public:string removeDuplicates(string s) {stack<char> st;for(int i 0; i < s.size(); i){char target s[i];if(!st.empty() && target st.top())st.pop();elsest.push(s[i]);}string ret…...