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

快速入门Spring Cloud Alibaba,轻松玩转微服务

1 快速入门Spring Cloud Alibaba,轻松玩转微服务

1.1 架构

架构图:架构图

1.2 项目结构

在这里插入图片描述

1.2.1 系统框架版本

版本适配查看:https://sca.aliyun.com/docs/2023/overview/version-explain/
Spring Boot Version :3.2.4
Spring Cloud Version :2023.0.1
Spring Cloud Alibaba Version : 2023.0.1.0

在这里插入图片描述

2 项目搭建

2.1 搭建

2.1.1 服务发现组件Nacos

功能: 注册与发现
版本: 2.3.2
下载:

docekr 下载获取,先翻墙之后执行:
docker pull nacos/nacos-server:v2.3.2
导出:
docker save -o nacos-v2.3.2.tar d3063c1db2bb
会出现在当前你执行命令的目录,之后传到服务器上
到服务器上执行:
docker load -i /data/install/docker-images/nacos-v2.3.2.tar
更改标签名:
docker tag d3063c1db2bb nacos/nacos-server:v2.3.2

启动nacos:
docker run --name nacos -d -p 8848:8848 -p 9848:9848 -e MODE=standalone nacos/nacos-server:v2.3.2
访问:
http://192.168.1.11:8848/nacos

介绍:

命名空间:不同的服务放在不同的命名空间下,隔离作用分组 例如:product

代码修改

(1)pom文件修改

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

(2)配置文件修改
spring:
application:
name: tlmall-storage
cloud:
nacos:
discovery:
server-addr: tlmall-nacos-server:8848
(3) 在启动类上使用 @EnableDiscoveryClient 注解开启服务注册与发现功能

参考 123 步骤到各个微服务中去修改,都启动后可以看到效果

在这里插入图片描述

实际调用:RestTemplate+LoadBalancer 实现服务调用

订单 想调用 库存的时候,通过负载均衡器来选择一个服务来调用
1) 订单服务的pom.xml 中添加LoadBalancer的依赖
在订单服务中

org.springframework.cloud spring-cloud-loadbalancer 2) 订单服务的application.yml中添加配置spring.cloud.loadbalancer.nacos.enabled=true

3)RestTemplate通过添加 @LoadBlanced 注解接入LoadBalancer
@Configuration
public class RestConfig {

@Bean
@LoadBalanced
RestTemplate restTemplate(){return new RestTemplate();
}

}
4)createOrder方法改造

        String storage_url = "http://cxqlmall-storage/storage/reduce-stock";Integer storageCode = restTemplate.postForObject(storage_url,storageDTO, Result.class).getCode();//openFeign远程调用
//Integer storageCode = storageService.reduceStock(storageDTO).getCode();if (storageCode.equals(COMMON_FAILED.getCode())) {throw new BusinessException("stock not enough");}// deduct balanceint price = count * 2;AccountDTO accountDTO = new AccountDTO();accountDTO.setUserId(userId);accountDTO.setPrice(price);//RestTemplate远程调用//String account_url = "http://localhost:8020/account/reduce-balance";//整合了Nacos+LoadBalaner,可以使用微服务名tlmall-account代替localhost:8020String account_url = "http://cxqlmall-account/account/reduce-balance";Integer accountCode = restTemplate.postForObject(account_url,accountDTO,Result.class).getCode();//openFeign远程调用
//Integer accountCode = accountService.reduceBalance(accountDTO).getCode();if (accountCode.equals(COMMON_FAILED.getCode())) {throw new BusinessException("balance not enough");}

整个调用的流程图基于负载均衡器:LoadBalancer

在这里插入图片描述

2.1.2 服务间调用组件-OpenFeign

功能: 服务间的远程调用
作用:在微服务架构中,LoadBalancer和OpenFeign虽然都提供了服务间调用的能力,但它们的设计目的和使用场景有所不同。

LoadBalancer主要关注于服务间的负载均衡,它可以帮助客户端在多个服务实例之间分配请求,以实现高可用性和性能优化。
而OpenFeign则提供了一种声明式的Web服务客户端编程模型,它使得编写服务间调用的代码更加简洁和直观。

官方文档:

https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/
OpenFeign是Spring Cloud框架中集成的声明式HTTP客户端工具

OpenFeign可以让远程调用服务达到像本地调用方法一样的体验。
Feign是Netflix开发的声明式、模板化的HTTP客户端,Feign可帮助我们更加便捷、优雅地调用HTTP API。Feign可以做到使用 HTTP 请求远程服务时就像调用本地方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个 HTTP 请求。

//本地调用
R result = orderService.findOrderByUserId(id);
//openFeign远程调用 orderService为代理对象
R result = orderService.findOrderByUserId(id);
Spring Cloud OpenFeign对Feign进行了增强,使其支持Spring MVC注解,从而使得Feign的使用更加方便。

版本:
可以从父POM中查找到<!-- Spring Cloud依赖 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency>
对应点进去能找到openfen对应的版本
<spring-cloud-openfeign.version>4.1.1</spring-cloud-openfeign.version>
怎么用:

1)引入依赖

org.springframework.cloud spring-cloud-starter-openfeign

2)在订单服务启动类上添加@EnableFeignClients注解,开启openFeign功能
在这里插入图片描述

3) 编写OpenFeign客户端,调用库存微服务和账户微服务
`
//微服务的名称
@FeignClient(name = “cxqlmall-storage”)
public interface StorageServiceFeignClient {
//对应的接口
@PostMapping(“/storage/reduce-stock”)
Result<?> reduceStock(@RequestBody StorageDTO productReduceStockDTO);

}
4)OrderServiceImpl 注入 StorageServiceFeignClient
@Autowired
private StorageServiceFeignClient storageService;

之后代码中调用:
Integer storageCode = storageServiceFeignClient.reduceStock(storageDTO).getCode();

`

在 Spring Cloud 2023.0.1.0 版本中,默认的负载均衡器是 Spring Cloud LoadBalancer

2.1.3 Nacos配置中心动态管理

作用:

配置中心就是一种统一管理各种应用配置的基础服务组件。

微服务为什么需要配置中心

一个微服务一个application.yml,100个微服务100个application.yml,如果注册中心地址变了,想象一下怎么改配置
配置中心使得配置信息集中管理,易于维护,并且可以动态更新配置
b25c33b8c4757b2dcba97c3d62412&pos_id=img-iDt38703-1736131903462)

文档

官方:https://sca.aliyun.com/docs/2023/user-guide/nacos/advanced-guide/

Nacos配置中心配置方式的变化
https://blog.csdn.net/u012760435/article/details/124631138

怎么用

在SpringBoot2.4这个大版本中有一项非常重要的改动:出于对云原生多配置文件的支持,默认关闭了对bootstrap.yml的使用。
解决方案
方案1: 重新启用bootstrap.yml(不推荐)
方案2: 使用spring.config.import(官方推荐)

spring:
config:
import:
- optional:nacos:${spring.application.name}.yml
- optional:nacos:db-common.yml #公共配置
spring.config.import: - optional:nacos:tlmall-order.yml:这一行是Spring Boot 2.4.0及以上版本引入的配置文件导入机制。
optional:nacos:tlmall-order.yml表示从Nacos配置中心导入名为tlmall-order.yml的配置文件,其中optional关键字意味着如果该配置文件在Nacos中不存在,那么Spring Boot将不会抛出异常,而是继续执行后续的初始化流程。

怎么用–订单服务整合Nacos配置中心

包括公共的
db-common.yml
服务独有的
nacos-discovery.yml
tlmall-order.yml

 Data ID :配置文件的名字

1)在Nacos控制台创建dataId(对应spring.config.import指定的配置文件名)
在这里插入图片描述

2)引入依赖

<!-- nacos-config 配置中心依赖 -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

3)在订单服务的application.yml 配置文件中配置 Nacos Config 地址并引入服务配置

server:port: 8030
spring:application:name: cxqlmall-orderconfig:import:- optional:nacos:${spring.application.name}.yml- optional:nacos:db-common.yml    #数据库公共配置- nacos:nacos-discovery.ymlcloud:nacos:config:server-addr: 192.168.1.11:8848file-extension: yml
logging:level:'[com.alibaba.cloud.nacos]': debug

spring.config.import: - optional:nacos:tlmall-order.yml:
这一行是Spring Boot 2.4.0及以上版本引入的配置文件导入机制。
optional:nacos:cxqlmall-order表示从Nacos配置中心导入名为cxqlmall-order.yml的配置文件,其中optional关键字意味着如果该配置文件在Nacos中不存在,那么Spring Boot将不会抛出异常,而是继续执行后续的初始化流程。

其余几个服务 参考上面的配置去修改

该配置必须放在 bootstrap.properties 文件中。此外 spring.cloud.nacos.config.namespace 的值是 namespace 对应的 id,id 值可以在 Nacos 的控制台获取。并且在添加配置时注意不要选择其他的 namespace,否则将会导致读取不到正确的配置

2.1.4 Seata解决分布式事务

  • 为什么要使用分布式事务
    一次业务操作需要跨多个数据源或需要跨多个系统进行远程调用,就会产生分布式事务问题
1)Seata是什么
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务
首选Seata AT 模式(官方推荐),可以做到业务无侵入
  • 官方文档
    https://seata.apache.org/zh-cn/docs/overview/what-is-seata/
  • Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。
  • 首选Seata AT 模式(官方推荐),可以做到业务无侵入
    https://seata.apache.org/zh-cn/docs/dev/mode/at-mode
2)Seata AT模式的工作流程
  • 非常重要的三个概念(要理解)
    TC (Transaction Coordinator) - 事务协调者
    维护全局和分支事务的状态,驱动全局事务提交或回滚。

    TM (Transaction Manager) - 事务管理器
    定义全局事务的范围:开始全局事务、提交或回滚全局事务。

    RM (Resource Manager) - 资源管理器
    管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

    比如,当前订单服务下单,调用库存服务扣减库存,调用账户服务扣减账户余额
    在这里插入图片描述

1) 订单服务要接入TM组件
下单操作需要开启全局事务(向TC申请一个全局事务XID),进入下单逻辑
如果下单正常,需要通知TC提交全局事务
如果下单异常,比如余额不够,需要通知TC回滚全局事务
2)订单服务,库存服务,账户服务都要接入RM组件
提交本地事务的同时,需要向TC注册分支事务信息
接收TC的通知,提交或回滚分支事务
3)TC是独立的服务
维护TM申请的全局事务信息和 RM提交的分支事务信息
TM通知TC全局事务提交或者回滚的时候,TM要通知RM分支事务提交或回滚

1. AT模式工作流程

https://www.processon.com/view/link/66dfbdf4df5e372d74e8009f?cid=66dfbddebc24f81739a5a7f5

2. Seata Server(TC)安装部署
 - [ ] 下载地址https://seata.apache.org/zh-cn/unversioned/release-history/seata-server- [ ] TC端存储模式---全局事务分支事务信息存储到哪儿?(TC存哪里)存文件或者数据库Seata1.x 支持的模式file:单机模式,全局事务会话信息内存中读写并持久化本地文件root.data,性能较高,但是只支持单机模式部署,生产环境不考虑。db:高可用模式,全局事务会话信息通过db共享,相应性能差些 (性能要求不高的话 用db模式)redis:1.3及以上版本支持,性能较高,存在事务信息丢失风险,请提前配置适合当前场景的redis持久化配置
----Seata2.x新增的Raft模式https://seata.apache.org/zh-cn/blog/seata-raft-detailed-explanation/利用Raft算法实现多个TC之间数据的同步。(不成熟)raft模式是最理想的方案,但是当前并不成熟,所以不用考虑。- [ ] 思考:RM和TM如何找到TC服务可以将TC服务注册到Nacos,RM和TC通过Nacos注册中心实现TC服务的发现![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/878c8143a02e4367ae073bbc2b3e6c3e.png)- [ ] 思考:TC的配置是不是也可以交个Nacos配置中心管理?注意:Seata的注册中心是作用于Seata自身的,和微服务自身配置的注册中心无关,但可以共用注册中心。可以创建一个seata的命名空间,区分seata的TC服务和业务微服务- [ ] 最终方案:db存储模式+Nacos(注册&配置中心)方式部署1. 前置环境准备1. db模式准备好seata的数据库sql文件:创建seata数据库,sql脚本在seata-server-2.0.0\seata\script\server\db\mysql.sql3. 准备好Nacos环境2.  配置Nacos注册中心配置将Seata Server注册到Nacos,修改/seata/conf/application.yml文件```xmlregistry:# support: nacos, eureka, redis, zk, consul, etcd3, sofatype: nacosnacos:application: seata-serverserver-addr: 192.168.1.11:8848namespace: seatagroup: SEATA_GROUPcluster: default```注意这里:需要自己到nacos新建命名空间 seata3.  配置Nacos配置中心   1)配置Nacos配置中心地址,修改conf/application.yml文件```xmlconfig:# support: nacos, consul, apollo, zk, etcd3type: nacosnacos:server-addr: 192.168.1.11:8848namespace: seatagroup: SEATA_GROUPdata-id: seataServer.properties```2)将seata server的配置上传配置至Nacos配置中心a) 获取/seata/script/config-center/config.txt,修改为db存储模式,并修改mysql连接配置
store.mode=db
store.lock.mode=db
store.session.mode=db
# mysql5.x
#store.db.driverClassName=com.mysql.jdbc.Driver
#store.db.url=jdbc:mysql://tlmall-mysql:3306/seata2.0.0?useUnicode=true&rewriteBatchedStatements=true
# mysql8.x
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://tlmall-mysql:3306/seata2.0.0?useUnicode=true&rewriteBatchedStatements=true&useSSL=false&characterEncoding=utf8&allowPublicKeyRetrieval=true
store.db.user=root
store.db.password=root

TC如何使用mysql8?

b) 配置事务分组, TC要与client(RM TM)配置的事务分组一致

事务分组:seata的资源逻辑,可以按微服务的需要,在应用程序(客户端)对自行定义事务分组,每组取一个名字。

集群:seata-server服务端一个或多个节点组成的集群cluster。 应用程序(客户端)使用时需要指定事务逻辑分组与Seata服务端集群的映射关系。
service.vgroupMapping.default_tx_group=default

微服务端要配置的值:default_tx_group

集群:default

事务分组如何找到后端Seata集群?

c) 在nacos配置中心中新建dataId为seataServer.properties的配置,配置内容为上面修改后的config.txt中的配置信息
在这里插入图片描述

完整版的nacos中的配置如下:

client.metadataMaxAgeMs=30000
client.rm.asyncCommitBufferLimit=10000
client.rm.lock.retryInterval=10
client.rm.lock.retryPolicyBranchRollbackOnConflict=true
client.rm.lock.retryTimes=30
client.rm.reportRetryCount=5
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.rm.sagaJsonParser=fastjson
client.rm.sqlParserType=druid
client.rm.tableMetaCheckEnable=true
client.rm.tableMetaCheckerInterval=60000
client.rm.tccActionInterceptorOrder=-2147482648
client.tm.commitRetryCount=5
client.tm.defaultGlobalTransactionTimeout=60000
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
client.tm.interceptorOrder=-2147482648
client.tm.rollbackRetryCount=5
client.undo.compress.enable=true
client.undo.compress.threshold=64k
client.undo.compress.type=zip
client.undo.dataValidation=true
client.undo.logSerialization=jackson
client.undo.logTable=undo_log
client.undo.onlyCareUpdateColumns=true
log.exceptionRate=100
metrics.enabled=false
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898
metrics.registryType=compact
server.distributedLockExpireTime=10000
server.enableParallelHandleBranch=false
server.enableParallelRequestHandle=true
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
server.recovery.asynCommittingRetryPeriod=1000
server.recovery.committingRetryPeriod=1000
server.recovery.rollbackingRetryPeriod=1000
server.recovery.timeoutRetryPeriod=1000
server.rollbackRetryTimeoutUnlockEnable=false
server.session.branchAsyncQueueSize=5000
server.session.enableBranchAsyncRemove=false
server.undo.logDeletePeriod=86400000
server.undo.logSaveDays=7
service.vgroupMapping.default_tx_group=default
store.db.branchTable=branch_table
store.db.datasource=druid
store.db.dbType=mysql
store.db.distributedLockTable=distributed_lock
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.globalTable=global_table
store.db.lockTable=lock_table
store.db.maxConn=30
store.db.maxWait=5000
store.db.minConn=5
store.db.password=root
store.db.queryLimit=100
store.db.url=jdbc:mysql://tlmall-mysql:3306/seata2.0.0?useUnicode=true&rewriteBatchedStatements=true&useSSL=false&characterEncoding=utf8&allowPublicKeyRetrieval=true
store.db.user=root
store.lock.mode=db
store.mode=db
store.publicKey=
store.session.mode=db
tcc.contextJsonParserType=fastjson
tcc.fence.cleanPeriod=1h
tcc.fence.logTableName=tcc_fence_log
transport.compressor=none
transport.enableRmClientBatchSendRequest=true
transport.enableTcServerBatchSendResponse=false
transport.enableTmClientBatchSendRequest=false
transport.heartbeat=true
transport.rpcRmRequestTimeout=30000
transport.rpcTcRequestTimeout=30000
transport.rpcTmRequestTimeout=30000
transport.serialization=seata
transport.server=NIO
transport.shutdown.wait=3
transport.threadFactory.bossThreadPrefix=NettyBoss
transport.threadFactory.bossThreadSize=1
transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
transport.threadFactory.clientSelectorThreadSize=1
transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
transport.threadFactory.shareBossWorker=false
transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
transport.threadFactory.workerThreadSize=default
transport.type=TCP
  1. 启动Seata Server
    windows点击bin目录下seata-server.bat直接启动
    启动成功,查看控制台http://127.0.0.1:7091,账号密码都是seata。
    在Nacos注册中心中可以查看到seata-server注册成功
    mac笔记本执行:
    sh seata-server.sh start
    之后看日志根据控制台提示,我是:seata-server is starting, you can check the /Users/apple/logs/seata/ *.log
    tail -f seata-server.8091.all.log
    即可看到启动日志
3. 微服务整合Seata AT模式实战
a. 业务场景

用户下单,订单服务调用库存服务扣减库存,调用账户服务扣减账户余额
事务发起者:订单服务
事务参与者:库存服务,账户服务

b. 订单服务(事务发起者)整合Seata

1)引入seata的依赖

<!-- seata 依赖-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
  1. 订单服务对应数据库中添加undo_log表(仅AT模式)
CREATE TABLE `undo_log` (`id` bigint NOT NULL AUTO_INCREMENT,`branch_id` bigint NOT NULL,`xid` varchar(100) NOT NULL,`context` varchar(128) NOT NULL,`rollback_info` longblob NOT NULL,`log_status` int NOT NULL,`log_created` datetime NOT NULL,`log_modified` datetime NOT NULL,PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

源码的init.sql中已经执行过的 不需要在执行
3)订单服务application.yml中添加seata配置

seata:# seata 服务的,事物分组,要与服务端配置service.vgroup_mapping的后缀对应tx-service-group: default_tx_groupregistry:# 指定nacos作为注册中心type: nacosnacos:application: seata-serverserver-addr: 192.168.1.11:8848namespace: seatagroup: SEATA_GROUPconfig:# 指定nacos作为配置中心type: nacosnacos:server-addr: 192.168.1.11:8848namespace: seatagroup: SEATA_GROUPdata-id: seataServer.properties

优化写法:
config:
import:
- optional:nacos:seata-client-${spring.profiles.active}.yml
在这里插入图片描述
新建配置:
在这里插入图片描述

4)订单服务作为全局事务发起者,在下单方法上添加@GlobalTransactional注解

c. 库存服务(事务参与者)整合Seata

和整合订单服务前三步一样
库存服务只需要在扣减库存方法上添加Spring事务@Transactional注解(注意加载service层哈)

d. 账户服务(事务参与者)整合Seata

配置同库存服务一样

4.Seata2.x常见问题
  1. 微服务启动报错:io.seata.config.exception.ConfigNotFoundException: service.vgroupMapping.default_tx_group configuration item is required
    产生的原因&解决思路
    原因:无法拉取到service.vgroupMapping.default_tx_group=default这个配置,也就找不到集群名为default的seata server服务
    思路1:检查下微服务端seata配置是否未配置事务分组seata.tx-service-group=default_tx_group
    思路2:检查下namespace和group配置server端和client端是否对应,特别注意seataServer.properties是否是SEATA_GROUP
  2. seata server报错:com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
    产生的原因&解决思路
    原因:无法连上数据库
    思路:检查下seataServer.properties中jdbc配置是否正确,检查jdbc版本和mysql版本是否匹配
5.重启所有服务,测试分布式事务是否生效
  • 通过Seata可以解决微服务分布式事务的问题
    下单:http://localhost:8080/order
    分布式事务成功场景,模拟正常下单、扣库存,扣余额
    分布式事务失败场景,模拟下单扣库存成功、扣余额失败,事务是否回滚
    有个问题:seata2.0.0 版本的bug,还是版本不兼容引起的,正常应该抛出业务封装好的异常现在抛出的不是,解决方式是 服务端seata-server版本改为1.7.0
    对异常问题处理的扩展链接
    在这里插入图片描述

正在更新中。。。。

流量不再怕:Sentinel限流保护服务
智能门卫:Gateway轻松守护微服务入口
监控可视化:Skywalking实时追踪服务链路
项目源码地址:https://gitee.com/javanewbie/spring-cloud-alibaba.git


http://www.mrgr.cn/news/82823.html

相关文章:

  • C++ shared_ptr进一步认知,为什么引用计数>2退出作用域都可以调用析构
  • 【RK3568笔记】Android修改开机动画
  • 平安社招 | 平安集团2025年社招笔试平安IQ新胜任力测评个性扫描16PF题库
  • 注册中心如何选型?Eureka、Zookeeper、Nacos怎么选
  • 历代iPhone运行内存大小和电池容量信息
  • 【JVM】总结篇之对象内存布局 执行引擎
  • 设计模式与游戏完美开发(3)
  • QT实现 端口扫描暂停和继续功能 3
  • 30、论文阅读:基于小波的傅里叶信息交互与频率扩散调整的水下图像恢复
  • 【HarmonyOS】鸿蒙应用点9图的处理(draw9patch)
  • Github提交Pull Request教程 Git基础扫盲(零基础易懂)
  • imageio 图片转mp4 保存mp4
  • 【FTP 协议】FTP主动模式
  • 【TextIn—智能文档解析与DocFlow票据AI自动化处理:赋能企业文档数字化管理与数据治理的双重利器】
  • 【学Rust开发CAD】1 环境搭建
  • WebRtc02: WebRtc架构、目录结构、运行机制
  • unity3d-搞个场景漫游如何实现Alpha
  • Java内存模型与线程
  • 《异步编程之美》— 全栈修仙《Java 8 CompletableFuture 对比 ES6 Promise 以及Spring @Async》
  • 2024年AI图像生成热门模型回顾
  • 苍穹外卖 项目记录 day03
  • Requests聚焦爬虫-数据解析
  • 服务器双网卡NCCL通过交换机通信
  • 【学Rust开发CAD】2 创建第一个工作空间、项目及库
  • 【SpringSecurity】二、自定义页面前后端分离
  • 鸿蒙APP之从开发到发布的一点心得