【SpringCloud】从入门到精通【上】
今天主播我把黑马新版微服务课程MQ高级之前的内容都看完了,虽然在看视频的时候也记了笔记,但是看完之后还是忘得差不多了,所以打算写一篇博客再温习一下内容。
课程坐标:黑马程序员SpringCloud微服务开发与实战
微服务
认识单体架构
单体架构(monolithic structure)
:顾名思义,整个项目中所有功能模块都在一个工程中开发;项目部署时需要对所有模块一起编译、打包;项目的架构设计、开发模式都非常简单。
像我们之前写过的
苍穹外卖,黑马点评
,他们虽然被拆分成了不同的模块,但是还是一个单体项目,通过Maven的聚合,让所有模块联系在一起,这种单体项目架构开发起来非常方便,例如我们简单写一个后台管理系统,或者是访问量较小的个人博客的后台系统的时候,单体项目是再简单不过的,但是如果我们用微服务来写,属实是大材小用。
但随着项目的业务规模越来越大,团队开发人员也不断增加,单体架构就呈现出越来越多的问题:
团队协作成本高
:试想一下,你们团队数十个人同时协作开发同一个项目,由于所有模块都在一个项目中,不同模块的代码之间物理边界越来越模糊。最终要把功能合并到一个分支,你绝对会陷入到解决冲突的泥潭之中。在公司当中一般都是用git来管理代码,你想象下,你开发一个模块,别人开发另一个模块,但是有一天,你们都对公共代码进行了修改,向git提交的时候是不是就会出现合并冲突。系统发布效率低
:任何模块变更都需要发布整个系统,而系统发布过程中需要多个模块之间制约较多,需要对比各种文件,任何一处出现问题都会导致发布失败,往往一次发布需要数十分钟甚至数小时。系统可用性差
:单体架构各个功能模块是作为一个服务部署,相互之间会互相影响,一些热点功能会耗尽系统资源,导致其它服务低可用。
关于系统可用性差,我们可以想象下,如果我们单体项目有两个服务,一个是
不太经常被访问的接口A
,而一个是经常被访问的热点接口B
,如果我们使用的是单体项目架构,那么热点接口B在被频繁访问的时候就会影响A的访问速度和性能,这就是单体项目的缺点,功能之间的相互影响比较大。而要想解决这些问题,就需要使用微服务架构了。
认识微服务
微服务架构
,首先是服务化,就是将单体架构中的功能模块从单体应用中拆分出来,独立部署为多个服务。同时要满足下面的一些特点:
单一职责
:一个微服务负责一部分业务功能,并且其核心数据不依赖于其它模块。团队自治
:每个微服务都有自己独立的开发、测试、发布、运维人员,团队人员规模不超过10人(2张披萨能喂饱)服务自治
:每个微服务都独立打包部署,访问自己独立的数据库。并且要做好服务隔离,避免对其它服务产生影响
那么,单体架构存在的问题有没有解决呢?
团队协作成本高?
- 由于服务拆分,每个服务代码量大大减少,参与开发的后台人员在1~3名,协作成本大大降低
系统发布效率低?
- 每个服务都是独立部署,当有某个服务有代码变更时,只需要打包部署该服务即可
系统可用性差?
- 每个服务独立部署,并且做好服务隔离,使用自己的服务器资源,不会影响到其它服务。
SpringCloud
微服务拆分以后碰到的各种问题都有对应的解决方案和微服务组件,而SpringCloud框架可以说是目前Java领域最全面的微服务组件的集合了。
而且SpringCloud依托于SpringBoot的自动装配能力,大大降低了其项目搭建、组件使用的成本。对于没有自研微服务组件能力的中小型企业,使用SpringCloud全家桶来实现微服务开发可以说是最合适的选择了!
SpringCloud官方网址
拆分微服务
拆分原则
服务拆分一定要考虑几个问题:什么时候拆?
如何拆?
什么时候拆
一般情况下,对于一个初创的项目,首先要做的是验证项目的可行性。因此这一阶段的首要任务是敏捷开发,快速产出生产可用的产品,投入市场做验证。为了达成这一目的,该阶段项目架构往往会比较简单,很多情况下会直接采用单体架构,这样开发成本比较低,可以快速产出结果,一旦发现项目不符合市场,损失较小。
如果这一阶段采用复杂的微服务架构,投入大量的人力和时间成本用于架构设计,最终发现产品不符合市场需求,等于全部做了无用功。
所以,对于大多数小型项目来说,一般是先采用单体架构,随着用户规模扩大、业务复杂后再逐渐拆分为微服务架构。这样初期成本会比较低,可以快速试错。但是,这么做的问题就在于后期做服务拆分时,可能会遇到很多代码耦合带来的问题,拆分比较困难(前易后难)。
而对于一些大型项目,在立项之初目的就很明确,为了长远考虑,在架构设计时就直接选择微服务架构。虽然前期投入较多,但后期就少了拆分服务的烦恼(前难后易)。
怎么拆
之前我们说过,微服务拆分时粒度要小,这其实是拆分的目标。具体可以从两个角度来分析:
高内聚
:每个微服务的职责要尽量单一,包含的业务相互关联度高、完整度高。低耦合
:每个微服务的功能要相对独立,尽量减少对其它微服务的依赖,或者依赖接口的稳定性要强。
高内聚首先是单一职责,但不能说一个微服务就一个接口,而是要保证微服务内部业务的完整性为前提。目标是当我们要修改某个业务时,最好就只修改当前微服务,这样变更的成本更低。
一旦微服务做到了高内聚,那么服务之间的耦合度自然就降低了。
当然,微服务之间不可避免的会有或多或少的业务交互,比如下单时需要查询商品数据。这个时候我们不能在订单服务直接查询商品数据库,否则就导致了数据耦合。而应该由商品服务对应暴露接口,并且一定要保证微服务对外接口的稳定性(即:尽量保证接口外观不变)。虽然出现了服务间调用,但此时无论你如何在商品服务做内部修改,都不会影响到订单微服务,服务间的耦合度就降低了。
明确了拆分目标,接下来就是拆分方式了。我们在做服务拆分时一般有两种方式:纵向拆分
横向拆分
所谓纵向拆分
,就是按照项目的功能模块来拆分。例如黑马商城中,就有用户管理功能、订单管理功能、购物车功能、商品管理功能、支付功能等。那么按照功能模块将他们拆分为一个个服务,就属于纵向拆分
。这种拆分模式可以尽可能提高服务的内聚性。
而横向拆分
,是看各个功能模块之间有没有公共的业务部分
,如果有将其抽取出来作为通用服务。例如用户登录是需要发送消息通知,记录风控数据,下单时也要发送短信,记录风控数据。因此消息发送、风控数据记录就是通用的业务功能,因此可以将他们分别抽取为公共服务:消息中心服务、风控管理服务。这样可以提高业务的复用性,避免重复开
发。同时通用业务一般接口稳定性较强,也不会使服务之间过分耦合。
拆分实操
这里我们以商品服务为例子,点击新建,选择新建模块
这里我们选择Java的Maven项目,JDK选择项目的JDK,父工程选择项目父工程
引入依赖
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>hmall</artifactId><groupId>com.heima</groupId><version>1.0.0</version></parent><modelVersion>4.0.0</modelVersion><artifactId>item-service</artifactId><properties><maven.compiler.source>11</maven.compiler.source><maven.compiler.target>11</maven.compiler.target></properties><dependencies><!--common--><dependency><groupId>com.heima</groupId><artifactId>hm-common</artifactId><version>1.0.0</version></dependency><!--web--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--数据库--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--mybatis--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId></dependency><!--单元测试--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency></dependencies><build><finalName>${project.artifactId}</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>
编写启动类
package com.hmall.item;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@MapperScan("com.hmall.item.mapper")
@SpringBootApplication
public class ItemApplication {public static void main(String[] args) {SpringApplication.run(ItemApplication.class, args);}
}
接下来就是拷贝与商品管理有关的代码到该微服务项目当中,然后写配置
server:port: 8081
spring:application:name: item-serviceprofiles:active: devdatasource:url: jdbc:mysql://${hm.db.host}:3306/hm-item?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghaidriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: ${hm.db.pw}
mybatis-plus:configuration:default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandlerglobal-config:db-config:update-strategy: not_nullid-type: auto
logging:level:com.hmall: debugpattern:dateformat: HH:mm:ss:SSSfile:path: "logs/${spring.application.name}"
knife4j:enable: trueopenapi:title: 商品服务接口文档description: "信息"email: zhanghuyi@itcast.cnconcat: 虎哥url: https://www.itcast.cnversion: v1.0.0group:default:group-name: defaultapi-rule: packageapi-rule-resources:- com.hmall.item.controller
注意在这里所有获取用户id的代码我们需要写死,后面我们会讲到如何获取。
服务调用
在微服务拆分的时候我们会发现,当一个微服务需要调用另一个微服务里的功能的时候,并不能直接注入Service
,最终结果就是查询到的购物车数据不完整,因此要想解决这个问题,我们就必须改造其中的代码,把原本本地方法调用,改造成跨微服务的远程调用(RPC,即Remote Produce Call)。最终就变成了这样
那么问题来了:我们该如何跨服务调用,准确的说,如何在cart-service中获取item-service服务中的提供的商品数据呢?
大家思考一下,我们以前有没有实现过类似的远程查询的功能呢?
有的兄弟,有的
,我们前端向服务端查询数据,其实就是从浏览器远程查询服务端数据。比如我们刚才通过Swagger测试商品查询接口,就是向http://localhost:8081/items这个接口发起的请求:
而这种查询就是通过http请求的方式来完成的,不仅仅可以实现远程查询,还可以实现新增、删除等各种远程请求。
假如我们在cart-service中能模拟浏览器,发送http请求到item-service,是不是就实现了跨微服务的远程调用了呢?
那么:我们该如何用Java代码发送Http的请求呢?
RestTemplate
Spring给我们提供了一个RestTemplate的API,可以方便的实现Http请求的发送。其中提供了大量的方法,方便我们发送http请求。可以看到常见的Get、Post、Put、Delete请求都支持,如果请求参数比较复杂,还可以使用exchange方法来构造请求。
我们先将其注入为一个Bean:
package com.hmall.cart.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;@Configuration
public class RemoteCallConfig {@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}
远程调用
可以看到,利用RestTemplate发送http请求与前端ajax发送请求非常相似,都包含四部分信息:
- ① 请求方式
- ② 请求路径
- ③ 请求参数
- ④ 返回值类型
ResponseEntity<List<ItemDTO>> response = restTemplate.exchange("http://localhost:8081/items?ids={ids}",HttpMethod.GET,null,new ParameterizedTypeReference<List<ItemDTO>>() {},Map.of("ids", CollUtil.join(itemIds, ","))
);
// 解析响应
if(!response.getStatusCode().is2xxSuccessful()){// 查询失败,直接结束return;
}
微服务的注册与发现
在上一章我们实现了微服务拆分,并且通过Http请求实现了跨微服务的远程调用。不过这种手动发送Http请求的方式存在一些问题。
试想一下,假如商品微服务被调用较多,为了应对更高的并发,我们进行了多实例部署,如图:
此时,每个item-service的实例其IP或端口不同,问题来了:
- item-service这么多实例,
cart-service如何知道每一个实例的地址?
- http请求要写url地址,
cart-service服务到底该调用哪个实例呢?
- 如果在运行过程中,
某一个item-service实例宕机,cart-service依然在调用该怎么办?
- 如果并发太高,
item-service临时多部署了N台实例
,cart-service如何知道新实例的地址?
为了解决上面的问题,就必须引入注册中心的概念了
注册中心
在微服务远程调用的过程中,包括两个角色:
服务提供者
:提供接口供其它微服务访问,比如item-service服务消费者
:调用其它微服务提供的接口,比如cart-service
在大型微服务项目中,服务提供者的数量会非常多,为了管理这些服务就引入了注册中心的概念。注册中心、服务提供者、服务消费者三者间关系如下:
流程如下
- 服务启动时就会注册自己的服务信息(服务名、IP、端口)到注册中心
- 调用者可以从注册中心订阅想要的服务,获取服务对应的实例列表(1个服务可能多实例部署)
- 调用者自己对实例列表负载均衡,挑选一个实例
- 调用者向该实例发起远程调用
那么当提供服务的宕机或者开启了新的服务了,服务调用者该怎么知道呢
心跳机制
:服务提供者会定期向注册中心发送请求,报告自己的健康状态,当注册中心长时间收不到提供者的心跳时
,会认为该实例宕机,将其从服务的实例列表中剔除
- 当服务有
新实例启动时
,会发送注册服务请求,其信息会被记录在注册中心的服务实例列表- 当注册中心
服务列表变更时
,会主动通知微服务,更新本地服务列表
Nacos注册中心
注册中心框架很多,目前国内流行的有三个
Eureka
:Netflix公司出品,目前被集成在SpringCloud当中,一般用于Java应用Nacos
:Alibaba公司出品,目前被集成在SpringCloudAlibaba中,一般用于Java应用Consul
:HashiCorp公司出品,目前集成在SpringCloud中,不限制微服务语言
以上几种注册中心都遵循SpringCloud中的API规范,因此在业务开发使用上没有太大差异。但是Nacos是阿里巴巴公司开源的,有中文API,方便我们使用。
Nacos官网
我们部署Nacos
是基于Docker
进行的,所以先要准备Nacos的相关表,然后我们需要修改Nacos
的配置文件,在运行的时候根据官方配置挂载指定目录
docker run -d \
--name nacos \
--env-file ./nacos/custom.env \
-p 8848:8848 \
-p 9848:9848 \
-p 9849:9849 \
--restart=always \
nacos/nacos-server:v2.1.0-slim
如果mysql和nacos在同一个网段下,这里直接写mysql的容器名字就可以,启动完成之后我们访问网址
http://虚拟机IP:8848/nacos/
,账号密码都是nacos
服务注册
引入依赖
<!--nacos 服务注册发现-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
配置nacos
spring:application:name: item-service # 服务名称cloud:nacos:server-addr: 虚拟机IP:8848 # nacos地址
在Nacos注册的时候,就会根据微服务的名字来注册,所以每个微服务的名字要唯一不重复
启动项目之后,我们在网站上可以看到该服务已经被注册
服务发现
服务调用者想要调用其他微服务就要,引入依赖
配置Nacos地址
发现并调用服务
走这三步
引入依赖
服务发现除了要引入nacos依赖以外,由于还需要负载均衡,因此要引入SpringCloud提供的LoadBalancer依赖。
<!--nacos 服务注册发现-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
可以发现,这里Nacos的依赖于服务注册时一致,这个依赖中同时包含了服务注册和发现的功能。因为任何一个微服务都可以调用别人,也可以被别人调用,即可以是调用者,也可以是提供者。
因此,等一会儿cart-service启动,同样会注册到Nacos
配置Nacos
spring:cloud:nacos:server-addr: IP:8848
发现并调用服务
接下来,服务调用者cart-service就可以去订阅item-service服务了。不过item-service有多个实例,而真正发起调用时只需要知道一个实例的地址。
因此,服务调用者必须利用负载均衡的算法,从多个实例中挑选一个去访问。常见的负载均衡算法有:
- 随机
- 轮询
- IP的hash
- 最近最少访问
- …
这里我们可以选择最简单的随机负载均衡。
服务的发现需要一个工具,
DiscoveryClient
,SpringCloud已经帮我们自动装配,我们可以直接注入使用
我们先通过这个工具,获取到所有命名为item-service
的实例集合,然后随机获取一个,获取它的URI
,然后调用。
OpenFegin
在上一章,我们利用Nacos实现了服务的治理,利用RestTemplate实现了服务的远程调用。但是远程调用的代码太复杂了,而且这种调用方式,与原本的本地方法调用差异太大,编程时的体验也不统一,一会儿远程调用,一会儿本地调用。
因此,我们必须想办法改变远程调用的开发模式,让远程调用像本地方法调用一样简单。而这就要用到OpenFeign组件了。
快速入门
引入依赖
<!--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></dependency>
启用OpenFeign
编写OpenFeign客户端
package com.hmall.cart.client;import com.hmall.cart.domain.dto.ItemDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;import java.util.List;@FeignClient("item-service")
public interface ItemClient {@GetMapping("/items")List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);
}
这里只需要声明接口,无需实现方法。接口中的几个关键信息:
@FeignClient("item-service")
:声明服务名称@GetMapping
:声明请求方式@GetMapping("/items")
:声明请求路径@RequestParam("ids") Collection<Long> ids
:声明请求参数List<ItemDTO>
:返回值类型
有了上述信息,OpenFeign就可以利用动态代理帮我们实现这个方法,并且向http://item-service/items
发送一个GET请求,携带ids为请求参数,并自动将返回值处理为List。
我们只需要直接调用这个方法,即可实现远程调用了。
使用FeignClient
先注入,后使用
连接池
Feign底层发起http请求,依赖于其它的框架。其底层支持的http客户端实现包括:
HttpURLConnection
:默认实现,不支持连接池Apache HttpClient
:支持连接池OKHttp
:支持连接池
引入依赖
<!--OK http 的依赖 -->
<dependency><groupId>io.github.openfeign</groupId><artifactId>feign-okhttp</artifactId>
</dependency>
配置开启连接池
feign:okhttp:enabled: true # 开启OKHttp功能
抽取Feign客户端
我们在里微服务调同一个接口的时候,如果没有抽取出来,那么每个微服务是不是都需要重新编写一下,那么有什么办法能解决这种重复编码的问题吗
这里有两种解决办法
- 思路1:抽取到微服务之外的公共module
- 思路2:每个微服务自己抽取一个module
方案1抽取更加简单,工程结构也比较清晰,但缺点是整个项目耦合度偏高。
方案2抽取相对麻烦,工程结构相对更复杂,但服务之间耦合度降低。
实战
这里我们选择方案1,只需要再创建一个模块,名为hm-all
引入需要的依赖,在里面编写接口就可以。但是这里我们需要注意一个包扫描的问题,我们每个微服务都在独立的包中,包括这个API模块也在独立的保重,boot项目默认扫描的是当前包及其子包 。这里我们有两种解决方案。
- 第一种是生命扫描包
- 第二种是声明要用的FeignClient,这里面是一个数组,可以声明多个
相关文章:
【SpringCloud】从入门到精通【上】
今天主播我把黑马新版微服务课程MQ高级之前的内容都看完了,虽然在看视频的时候也记了笔记,但是看完之后还是忘得差不多了,所以打算写一篇博客再温习一下内容。 课程坐标:黑马程序员SpringCloud微服务开发与实战 微服务 认识单体架构 单体架…...
如何给路由器配置代理IP?更改网络ip地址时出现错误怎么解决?
在现代网络环境中,无论是家庭用户还是企业用户,经常需要配置路由器以实现网络访问的灵活性和匿名性。其中,给路由器配置代理IP是一个常见的需求,尤其是在需要绕过地域限制、增强网络安全或进行匿名浏览时。然而,配置过…...
程序化广告行业(70/89):ABTester系统助力落地页优化实践
程序化广告行业(70/89):ABTester系统助力落地页优化实践 在程序化广告领域摸爬滚打多年,深知持续学习和知识共享的重要性。写这篇博客,就是希望能和大家一起深入探索程序化广告行业,共同学习、共同进步。今…...
远程监控系统项目里练习
1、项目目标 设备端: (1)基于stm32mp157开发板,裁剪linux5.10.10,完成ov5640摄像头移植; (2)完成用户层程序,完成对摄像头的控制及与云端服务的数据交互。 云端&…...
Spring Boot 通过全局配置去除字符串类型参数的前后空格
1、问题 避免前端输入的字符串参数两端包含空格,通过统一处理的方式,trim掉空格 2、实现方式 /*** 去除字符串类型参数的前后空格* author yanlei* since 2022-06-14*/ Configuration AutoConfigureAfter(WebMvcAutoConfiguration.class) public clas…...
设计模式 --- 观察者模式
设计模式 --- 观察者模式 什么是观察者模式观察者模式典型应用 --- C#中的事件使用观察者模式实现事件处理机制 什么是观察者模式 观察者模式(Observer Pattern)是一种行为型设计模式,用于在对象之间建立一对多的依赖关系。当一个对象&#x…...
组播网络构建:IGMP、PIM 原理及应用实践
IP组播基础 组播基本架构 组播IP地址 一个组播IP地址并不是表示具体的某台主机,而是一组主机的集合,主机声明加入某组播组即标识自己需要接收目的地址为该组播地址的数据IP组播常见模型分为ASM模型和SSM模型ASM:成员接收任意源组播数据&…...
Java常见的23种设计模式
Java常见的23种设计模式 大家好,我是钢板兽! 本文将系统梳理 Java 的设计模式,涵盖创建型、结构型和行为型三大类,结合定义、原理、优点、应用场景、示例代码,帮助你初步了解常见的23种设计模式。 一、设计模式分类…...
兔单B细胞单抗制备服务
1.兔单B细胞技术原理 兔单B细胞技术是近年来新发展的一类快速制备单克隆抗体的技术,是一种通过分离和单克隆化兔子体内的B细胞来制备单一来源的高特异性抗体的方法。基于流式细胞分选技术进行单B细胞单抗制备,利用每个B细胞只含有一个功能性重链可变区D…...
MySQL基础 [六] - 内置函数+复合查询+表的内连和外连
内置函数一般要用select调用 内置函数 日期函数 current_date函数 current_date函数用于获取当前的日期。如下: current_time函数 current_time函数用于获取当前的时间。如下: now函数 now函数用于获取当前的日期时间。如下: date函数 dat…...
nginx路径匹配的优先级
在 Nginx 配置中,当请求 /portal/agent/sse 时,会匹配 location ~* /sse$ 规则,而不是 location /portal。原因如下: 匹配规则解析 location ~* /sse$ ~* 表示 不区分大小写的正则匹配/sse$ 表示以 /sse 结尾的路径匹配结果&#…...
tcp/ip攻击及防范
作为高防工程师,我每天拦截数以万计的恶意流量,其中TCP/IP协议层攻击是最隐蔽、最具破坏性的威胁之一。常见的攻击手法包括: 1. SYN Flood攻击:攻击者发送大量伪造的SYN包,耗尽服务器连接资源,导致正常用…...
2025年3月中国电子学会青少年软件编程(Python)等级考试试卷(一级)答案 + 解析
更多真题在线练习系统:历年真题在线练习系统 一、单选题 1、下列哪个软件不能运行 Python 程序?( ) A、JupyterNotebook B、Pycharm C、原版的Scratch D、IDLE 正确答案:C 答案解析:本题考察的 Pyt…...
TreeMap 核心知识点与面试题解析
TreeMap 核心知识点与面试题解析 一、TreeMap 基础概念 TreeMap 是 Java 集合框架中基于 红黑树(Red-Black Tree) 实现的 Map,具有以下特点: 有序性:默认按 key 的自然顺序(Comparable)或自定…...
深入理解 DevOps 与 CI/CD:概念、流程及优势
在当今快速发展的数字化时代,软件开发和交付的速度与质量成为企业在激烈竞争中脱颖而出的关键因素。DevOps 和 CI/CD 作为现代软件开发领域的重要理念和实践,正深刻地改变着软件开发生命周期的运作方式。本文将深入探讨 DevOps 的概念,详细解析 CI/CD 的内涵、管道阶段以及实…...
Flutter BloC 架构入门指南
BLoC (Business Logic Component) 是 Flutter 中一种流行的状态管理架构,它可以帮助你将业务逻辑与 UI 分离,使代码更清晰、可测试性更强。 核心概念 1. BloC 的核心组件 Events:用户交互或系统事件(如按钮点击、网络请求完成&…...
OpenHarmony-AI调研
OpenHarmony-AI调研 文章目录 OpenHarmony-AI调研前言一、当前版本部署组件二、AI架构1.mindspore-lite2.ai_engine3.neural_network_runtime4.intelligent_voice_framework5.HDI驱动 三、应用1.命令行以及web运行deepseek-r12.与deepseek通过语音进行交互3.物品识别4.人脸识别…...
zk基础—zk实现分布式功能
1.zk实现数据发布订阅 (1)发布订阅系统一般有推模式和拉模式 推模式:服务端主动将更新的数据发送给所有订阅的客户端。 拉模式:客户端主动发起请求来获取最新数据(定时轮询拉取)。 (2)zk采用了推拉相结合来实现发布订阅 首先客户端需要向服务端注册自己关…...
Tips:用proxy解决前后端分离项目中的跨域问题
在前后端分离项目中,"跨域问题"是浏览器基于同源策略(Same-Origin Policy)对跨域请求的安全限制。当你的前端(如运行在 http://localhost:3000 )和后端(如运行在 http://localhost:8080 &#…...
JMeterPlugins-Standard-1.4.0 插件详解:安装、功能与使用指南
JMeterPlugins-Standard-1.4.0 是 Apache JMeter(一款流行的开源负载和性能测试工具)的插件包,它扩展了 JMeter 的功能,提供了更多监听器(Listeners)、采样器(Samplers)和辅助组件&a…...
JMeter 中,Token 和 Cookie 的区别及实际应用
在 JMeter 中,Token 和 Cookie 都是用于处理用户会话和身份验证的机制,但它们的 工作原理、存储方式 和 应用场景 有显著区别。以下是详细对比和实际应用指南: 1. 核心区别 特性Token (如 JWT、OAuth)Cookie存储位置通常存储在 HTTP 请求头(如 Authorization: Bearer <t…...
蓝桥杯真题——好数、R格式
目录 蓝桥杯2024年第十五届省赛真题-好数 【模拟题】 题目描述 输入格式 输出格式 样例输入 样例输出 提示 代码1:有两个案例过不了,超时 蓝桥杯2024年第十五届省赛真题-R 格式 【vector容器的使用】 题目描述 输入格式 输出格式 样例输入…...
JavaScript惰性加载优化实例
这是之前的一位朋友的酒桌之谈,他之前负责的一个电商项目,刚刚开发万,首页加载时间特别长,体验很差,所以就开始排查,发现是在首页一次性加载所有js导致的问题,这个问题在自己学习的时候并不明显…...
0_Pytorch中的张量操作
[引言]张量的概念 1.基本概念 张量是一个通用的多维数组,可以表示标量(0 维)、向量(1 维)、矩阵(2 维)以及更高维度的数据。张量是 PyTorch 中的核心数据结构,用于表示和操作数据。…...
Java面试43-常见的限流算法有哪些?
限流算法是一种系统保护策略,主要是避免在流量高峰导致系统被压垮,造成系统不可用的问题。 常见的限流算法有五种: 计数器限流,一般用在单一维度的访问频率限制上,比如短信验证码每隔60s只能发送一次,或者…...
牛客网:树的高度 ← 根节点为 0 号节点
【题目来源】 https://www.nowcoder.com/questionTerminal/4faa2d4849fa4627aa6d32a2e50b5b25 【题目描述】 现在有一棵合法的二叉树,树的节点都是用数字表示,现在给定这棵树上所有的父子关系,求这棵树的高度。 【输入格式】 输入的第一行表…...
Linux:进程程序替换execl
目录 引言 1.单进程版程序替换 2.程序替换原理 3.6种替换函数介绍 3.1 函数返回值 3.2 命名理解 3.3 环境变量参数 引言 用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),我们所创建的所有的子进程,执行的代码&#x…...
⑩数据中心M-LAG 实战
一、配置指导自己去看今天操作的是M-LAG 基础实验 二、配置代码信息回顾 ### 1、配置 M-LAG 系统 MAC 地址<H3C>system-view[H3C]m-lag system-mac ?H-H-H MAC address2a7a-53ee-0100 Bridge MAC address[H3C]m-lag system-mac### 2、配置 M-LAG 系统编号…...
delphi idtcpserver 搭建tcp ,ssl协议服务端
如果想用indy idtcpserver实现tcp ssl,那么正是你需要的 首先生成证书: 2、windows生成pem证书 - 站着说话不腰疼 - 博客园 有证书后 idtcpserver 用的三个证书, IdServerIOHandlerSSLOpenSSL1.SSLOptions.CertFile = ca.crt IdServerIOHandlerSSLOpenSSL1.SSLOptions.…...
如何实现外观模式?
一、模式理解(用快递驿站比喻) 想象你网购了5件商品,分别来自不同快递公司。 外观模式就像小区门口的快递驿站,你不需要知道中通怎么分拣、顺丰怎么运输,只要到驿站报取件码就能拿到所有包裹。 在前端开发中…...
深入解析 Linux 文件系统权限:从基础到高级实践
引言 在 Linux 系统中,文件系统权限是保障数据安全和多用户协作的核心机制。想象这样一个场景: 你的服务器上有多个团队共享项目文件 财务数据必须严格保密,仅允许指定人员访问 开发团队需要共同编辑代码,但禁止随意删除他人文…...
GZ036区块链卷一 EtherStore合约漏洞详解
题目 pragma solidity >0.8.3;contract EtherStore {mapping(address > uint) public balances;function deposit() public payable {balances[msg.sender] msg.value;emit Balance(balances[msg.sender]);}function withdraw() public {uint bal balances[msg.sender…...
医药流通行业批发公司IT运维转型:Prometheus+Grafana监控Spring Boot 3应用实践
一、引言:医药流通行业IT运维挑战与工具换代需求 在医药流通行业批发领域,业务的核心在于供应链的高效运转、订单处理的精准及时以及库存管理的动态平衡。随着互联网医疗的兴起和电商平台的渗透,传统医药批发企业正加速向数字化、智能化转型…...
编程助手fitten code使用说明(超详细)(vscode)
这两年 AI 发展迅猛,作为开发人员,我们总是追求更快、更高效的工作方式,AI 的出现可以说改变了很多人的编程方式。 AI 对我们来说就是一个可靠的编程助手,给我们提供了实时的建议和解决方,无论是快速修复错误、提升代…...
金融大模型
FinGPT 数据集:https://github.com/AI4Finance-Foundation/FinGPT/tree/master/fingpt/FinGPT-v3 FinGPT v3 系列是在新闻和微博情绪分析数据集上使用 LoRA 方法进行微调的LLM,在大多数金融情绪分析数据集上取得了最佳分数。 FinGPT v3.1 使用 chatgl…...
【Pandas】pandas DataFrame infer_objects
Pandas2.2 DataFrame Conversion 方法描述DataFrame.astype(dtype[, copy, errors])用于将 DataFrame 中的数据转换为指定的数据类型DataFrame.convert_dtypes([infer_objects, …])用于将 DataFrame 中的数据类型转换为更合适的类型DataFrame.infer_objects([copy])用于尝试…...
011_异常、泛型和集合框架
异常、泛型和集合框架 异常Java的异常体系异常的作用 自定义异常异常的处理方案异常的两种处理方式 泛型泛型类泛型接口泛型方法、通配符和上下限泛型支持的类型 集合框架集合体系结构Collection Collection集合Collection的遍历方式认识并发修改异常问题解决并发修改异常问题的…...
QTSql全解析:从连接到查询的数据库集成指南
概览 与数据库的有效集成是确保数据管理效率和应用性能的关键,Qt框架就提供了强大的QtSql模块,使得开发者能够轻松地进行数据库操作,包括连接、查询执行以及结果处理等 一、引入QtSql模块 首先,需要在项目中引入QtSql模块&…...
docker快捷打包脚本(ai版)
直接进入主题: 用这个脚本前提是你本地可以拉镜像仓库的镜像,并且在 本地有了,然后将所有的镜像tag写在一个文件中,和下面docker_tags.txt 对应,文件叫什么,脚本里对应改什么,给小白说的 #!/bi…...
分布式防护节点秒级切换:实战配置与自动化运维
摘要:针对DDoS攻击导致节点瘫痪的问题,本文基于群联AI云防护的智能调度系统,详解如何实现节点健康检查、秒级切换与自动化容灾,并提供Ansible部署脚本。 一、分布式节点的核心价值 资源分散:攻击者难以同时击溃所有节…...
TBE(TVM的扩展)
算子 张量 一个张量只有一种数据类型 在内存中只能线性存储,最终形成一个长的一维数组 晟腾AI的数据格式 AIPP是对我们常见的数据格式转化成AI core支持的数据格式 广播机制 TVM TBE的第一种开发方式:DSL TBE的第二种开发方式:TVM TBE的第…...
Jenkins配置的JDK,Maven和Git
1. 前置 在配置前,我们需要先把JDK,Maven和Git安装到Jenkins的服务器上。 (1)需要进入容器内部,执行命令:docker exec -u root -it 容器号/容器名称(2选1) bash -- 容器名称 dock…...
核心案例 | 湖南汽车工程职业大学无人机操控与编队技术实验室
核心案例 | 湖南汽车工程职业大学无人机操控与编队技术实验室 为满足当今无人机行业应用需求,推动无人机技术的教育与实践深度融合,北京卓翼智能科技有限公司旗下品牌飞思实验室与湖南汽车工程职业大学强强联手,共同建设无人机操控与编队技术…...
【阻抗匹配】
自动匹配的实现: 检测反射信号:通过传感器(如定向耦合器)监测反射功率或驻波比(SWR),判断是否失配。控制单元:利用微控制器或专用芯片(如FPGA)分析检测数据&a…...
micro常用快捷键
micro常用快捷键 以下是 micro 编辑器 的常用快捷键整理,按功能分类清晰,方便快速查阅: 1. 基础操作 快捷键功能Ctrl S保存文件Ctrl Q退出编辑器Ctrl O打开文件Ctrl E打开命令栏(输入命令)Ctr…...
DNS域名解析服务
目录 DNS系统 DNS系统的作用 DNS系统的类型(服务器分类) 1. 递归解析器(Recursive Resolver) 2. 根域名服务器(Root Name Server) 3. 顶级域服务器(TLD Name Server)…...
Linux的目录结构
倒根树状结构 【注意】 / 表示根目录,相当于Windows的C盘 进入跟目录命令: cd / /bin:存放的系统命令或二进制文件,如:cd ls cp等 /sbin /usr/bin /dev:存放的设备节点文件 , 驱动文件 /…...
【Python】Python 100题 分类入门练习题 - 新手友好
Python 100题 分类入门练习题 - 新手友好篇 - 整合篇 一、数学问题题目1:组合数字题目2:利润计算题目3:完全平方数题目4:日期天数计算题目11:兔子繁殖问题题目18:数列求和题目19:完数判断题目21…...
Three.js 系列专题 7:性能优化与最佳实践
内容概述 随着 3D 场景复杂度的增加,性能优化变得至关重要。Three.js 项目可能因几何体数量、纹理大小或渲染设置而变慢。本专题将介绍减少 draw call、优化纹理和使用调试工具的最佳实践。 学习目标 学会减少 draw call 和几何体复杂度。掌握纹理压缩与内存管理。使用 Stat…...
特权FPGA之Johnson移位
完整代码: module johnson(clk,rst_n,led,sw1_n,sw2_n,sw3_n);input clk; //时钟信号,50MHz input rst_n; //复位信号,低电平有效 output[3:0] led; //LED控制,1--灭…...