前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >SpringBoot 物理线程、虚拟线程、Webflux 性能全面对比!

SpringBoot 物理线程、虚拟线程、Webflux 性能全面对比!

作者头像
用户1220090
发布于 2025-05-10 02:55:46
发布于 2025-05-10 02:55:46
18200
代码可运行
举报
文章被收录于专栏:芋道源码芋道源码
运行总次数:0
代码可运行

👉这是一个或许对你有用的开源项目

国产 Star 破 10w+ 的开源项目,前端包括管理后台 + 微信小程序,后端支持单体和微服务架构

功能涵盖 RBAC 权限、SaaS 多租户、数据权限、商城、支付、工作流、大屏报表、微信公众号等等功能:

  • Boot 地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro
  • Cloud 地址:https://gitee.com/zhijiantianya/yudao-cloud
  • 视频教程:https://doc.iocoder.cn

来源:丛林 medium.com

虽然这个场景看起来似乎也很简单,但它概括了 Web 开发领域中经常遇到的现实挑战。

介绍

在本文中,我们将深入探讨所有同级产品之间的友好比较,即具有「物理线程、虚拟线程和 Webflux 的 SpringBoot」 ,重点关注它们在特定用例场景中的性能。我们已经探索了标准 SpringBoot 应用程序如何与 webflux 相媲美,但现在,我们引入一个关键的区别:

带有虚拟线程的 Spring Boot

我们熟悉 SpringBoot,但有一点不同——它在虚拟线程而不是传统的物理线程上运行。虚拟线程是并发领域的游戏规则改变者。这些轻量级线程简化了开发、维护和调试高吞吐量并发应用程序的复杂任务。

虽然虚拟线程仍然在底层操作系统线程上运行,但它们带来了显着的效率改进。当虚拟线程遇到阻塞 I/O 操作时,Java 运行时会暂时挂起它,从而释放关联的操作系统线程来为其他虚拟线程提供服务。这个优雅的解决方案优化了资源分配并增强了整体应用程序响应能力。

考虑到这些有趣的设置,让我们更深入地研究我们的性能比较。撰写本文是为了解决最常见的请求之一,即查看物理、虚拟和 Webflux 在实际用例中的比较。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 视频教程:https://doc.iocoder.cn/video/

测试环境及软件版本

我们的性能测试是在配备 16GB RAM 的 MacBook Pro M1 上进行的,确保了可靠的测试平台。用于这些测试的软件堆栈包括:

  • SpringBoot 3.1.3(在Java 20上运行)
  • 启用预览模式以获得虚拟线程的强大功能
  • jjwt用于JWT验证和解码,增强我们应用程序的安全性。
  • mysql-connector-java 用于执行 MySQL 查询,维护数据完整性和一致性。

负载测试和 JWT

为了评估我们的应用程序在不同负载下的性能,我们使用了开源负载测试工具 Bombardier。我们的测试场景涉及预先创建的 100000 个 JWT 列表。在测试过程中,Bombardier 从该池中随机选择 JWT,并将它们包含在 HTTP 请求的授权标头中。

Bombardier开源地址: https://github.com/codesenberg/bombardier/

MySQL 数据库架构

用于这些性能测试的 MySQL 数据库有一个名为 users 的表。该表设计有 6 列,足以模拟我们应用程序中的真实数据交互,使我们能够评估它们的响应能力和可扩展性。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql> desc users;
+--------+--------------+------+-----+---------+-------+
| Field  | Type         | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+-------+
| email  | varchar(255) | NO   | PRI | NULL    |       |
| first  | varchar(255) | YES  |     | NULL    |       |
| last   | varchar(255) | YES  |     | NULL    |       |
| city   | varchar(255) | YES  |     | NULL    |       |
| county | varchar(255) | YES  |     | NULL    |       |
| age    | int          | YES  |     | NULL    |       |
+--------+--------------+------+-----+---------+-------+
6 rows in set (0.00 sec)

用户数据库已准备好包含 100000 条用户记录的初始数据集。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql> select count(*) from users;
+----------+
| count(*) |
+----------+
|    99999 |
+----------+
1 row in set (0.01 sec)

在我们对 SpringBoot 物理线程、虚拟线程和 Webflux 进行友好性能评估的背景下,了解关键的数据关系至关重要。具体来说,在JSON Web Token(JWT)有效负载中,每个电子邮件条目直接对应于存储在 MySQL 数据库中的一条用户记录。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud
  • 视频教程:https://doc.iocoder.cn/video/

代码

SpringBoot(物理线程)

配置信息

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
server.port=3000
spring.datasource.url= jdbc:mysql://localhost:3306/testdb?useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.username= dbuser
spring.datasource.password= dbpwd
spring.jpa.hibernate.ddl-auto= update
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect

实体类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.example.demo;

import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
@Table(name = "users")
publicclass User {
@Id
private String email;

private String first;

private String last;

private String city;

private String county;

privateint age;

public String getId() {
    return email;
  }

public void setId(String email) {
    this.email = email;
  }

public String getFirst() {
    return first;
  }

public void setFirst(String name) {
    this.first = name;
  }

public String getLast() {
    return last;
  }

public void setLast(String name) {
    this.last = name;
  }

public String getEmail() {
    return email;
  }

public void setEmail(String email) {
    this.email = email;
  }

public String getCity() {
    return city;
  }

public void setCity(String city) {
    this.city = city;
  }

public String getCounty() {
    return county;
  }

public void setCounty(String county) {
    this.county = county;
  }

public int getAge() {
    return age;
  }

public void setAge(int age) {
    this.age = age;
  }
}

启动类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class UserApplication {

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

Controller层

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.example.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Optional;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import java.security.Key;
import com.example.demo.UserRepository;
import com.example.demo.User;

@RestController
publicclass UserController {

    @Autowired
    UserRepository userRepository;

    private SignatureAlgorithm sa = SignatureAlgorithm.HS256;
    private String jwtSecret = System.getenv("JWT_SECRET");

    @GetMapping("/")
    public User handleRequest(@RequestHeader(HttpHeaders.AUTHORIZATION) String authHdr) {
        String jwtString = authHdr.replace("Bearer","");
        Claims claims = Jwts.parser()
            .setSigningKey(jwtSecret.getBytes())
            .parseClaimsJws(jwtString).getBody();

        Optional<User> user = userRepository.findById((String)claims.get("email"));
        return user.get();
    }
}

接口类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.example.demo;

import org.springframework.data.repository.CrudRepository;
import com.example.demo.User;

public interface UserRepository extends CrudRepository<User, String> {

}

Springboot(虚拟线程)

其余代码基本照搬上述 「物理线程」 , 启动类修改如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer;
import org.springframework.context.annotation.Bean;
import java.util.concurrent.Executors;

@SpringBootApplication
publicclass UserApplication {

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

    @Bean
    public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() {
        return protocolHandler -> {
            protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
        };
    }
}

SpringBoot(webflux)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
server.port=3000
spring.r2dbc.url=r2dbc:mysql://localhost:3306/testdb?allowPublicKeyRetrieval=true&ssl=false
spring.r2dbc.username=dbuser
spring.r2dbc.password=dbpwd
spring.r2dbc.pool.initial-size=10
spring.r2dbc.pool.max-size=10

启动类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package webfluxdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer;
import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator;
import org.springframework.web.reactive.config.EnableWebFlux;

import io.r2dbc.spi.ConnectionFactory;

@EnableWebFlux
@SpringBootApplication
publicclass UserApplication {

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

}

Controller层代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package webfluxdemo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.http.HttpHeaders;

import webfluxdemo.User;
import webfluxdemo.UserService;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import java.security.Key;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@RestController
@RequestMapping("/")
publicclass UserController {
@Autowired
  UserService userService;

private SignatureAlgorithm sa = SignatureAlgorithm.HS256;
private String jwtSecret = System.getenv("JWT_SECRET");

@GetMapping("/")
@ResponseStatus(HttpStatus.OK)
public Mono<User> getUserById(@RequestHeader(HttpHeaders.AUTHORIZATION) String authHdr) {
    String jwtString = authHdr.replace("Bearer","");
    Claims claims = Jwts.parser()
        .setSigningKey(jwtSecret.getBytes())
        .parseClaimsJws(jwtString).getBody();
    return userService.findById((String)claims.get("email"));
  }
}

接口类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package webfluxdemo;

import org.springframework.data.r2dbc.repository.R2dbcRepository;
import org.springframework.stereotype.Repository;

import webfluxdemo.User;

public interface UserRepository extends R2dbcRepository<User, String> {

}

Service层代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package webfluxdemo;

import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import webfluxdemo.User;
import webfluxdemo.UserRepository;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Service
publicclass UserService {

@Autowired
  UserRepository userRepository;

public Mono<User> findById(String id) {
    return userRepository.findById(id);
  }
}

结果

为了评估性能,我们进行了一系列严格的测试。每个测试由100万个请求组成,我们评估了它们在不同并发连接级别(50、100和300)下的性能。

现在,让我们深入研究结果,以图表形式呈现:

所用时间对比

每秒请求数

最小延迟

10%延迟

25%延迟

平均延迟

中位数延迟

75%延迟

90%延迟

99%延迟

最高延迟

平均CPU使用率

平均内存使用率

分析

在此设置中,即使用MySQL驱动程序时,虚拟线程提供的性能最低、Webflux保持遥遥领先。

星球的内容包括:项目实战、面试招聘、源码解析、学习路线。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-05-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 芋道源码 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
Airbnb从Buck 迁移到 Bazel,大幅改善开发者体验
随着其他组织将他们的构建管道迁移到Bazel 之后,Airbnb 也发布了一个详细的说明,分享了他们弃用 Buck 并改善构建时间以及项目生成和加载时间的过程。
深度学习与Python
2024/02/29
1710
Airbnb从Buck 迁移到 Bazel,大幅改善开发者体验
Bazel 7 发布:全新模块化依赖管理、无字节构建与多目标构建性能提升
最近在 BazelCon 23 上宣布,Bazel 7 推出了多年来一直在开发中的一系列新功能,其中包括全新的模块化外部依赖管理系统 Bzlmod、全新优化的“Build without the Bytes”模式、得益于 Project Skymeld 的多目标构建性能改进等等。
深度学习与Python
2024/01/04
4590
Spotify 移动工程平台迁移:将 Android 和 iOS 代码库迁移到 Bazel
作者 | Aditya Kulkarni 译者 | 刘雅梦 策划 | 丁晓昀 最近,Spotify 移动工程团队详细介绍了他们最近的平台迁移经验。根据移动工程战略计划,该团队将他们的 Android 和 iOS 代码库迁移到了谷歌的开源构建系统 Bazel 上。 来自 Spotify 移动工程团队的 Mariana Ardoino 和 Raul Herbster 在一篇博客文章中探讨了从迁移中获得的经验教训。迁移工作影响了 Spotify 的 100 多个团队。团队认识到,不同规模和复杂性的迁移将
深度学习与Python
2023/03/29
4200
Spotify 移动工程平台迁移:将 Android 和 iOS 代码库迁移到 Bazel
Slack 工程师如何解决最常见的移动开发痛点
作者 | Sergio De Simone 译者 | 马可薇 策划 | 丁晓昀 Slack 的开发者体验团队是由 8 个人专门负责的,该团队是为解决伴随组织和开发团队壮大而不断增长的成本问题。在 Slack 开发过程中成本最为高昂的部分,在于工程师需花费大量精力合并代码冲突、长时间的 CI 工作、片状测试和 CI 基础设施故障。 虽然可以让开发者们学习部分问题的解决方法,但随着团队的成长,所要花费的时间和成本是极不现实的。拥有一个特殊团队专注解决这类问题,不仅可以让开发团队效率更高,还能确保开发团
深度学习与Python
2023/03/29
5170
Slack 工程师如何解决最常见的移动开发痛点
如何解决 iOS 环境搭建与 APP 打包速度问题
随着 Flutter 等跨端框架的出现,业务开发同学经常需要在 Android/IOS 上跨端进行业务开发,问题定位等。新的不熟悉的环境的搭建总会遇到各种各样的问题,导致搭建失败,特别是 IOS 开发环境,是最复杂的,不仅环境搭建繁琐,而且切分支后的打包速度很慢,所以我们设计实现了两个工具,用于优化闲鱼 IOS 开发体验。
编程怪才-凌雨画
2020/09/18
2.6K0
Kotlin Multiplatform Mobile 进入 Beta 测试
作者 | Sergio De Simone 译者 | 平川 策划 | 丁晓昀 Kotlin Multiplatform Mobile 由 JetBrains 创建,支持使用 Kotlin 从单个代码库创建具有原生 UI 的 iOS 和 Android 应用。Kotlin Multiplatform Mobile 已经退出实验阶段,进入 Beta 测试。 Kotlin Multiplatform Mobile 是一个用于 iOS 和 Android 应用开发的 SDK,它让你可以将网络、数据存储和分
深度学习与Python
2023/03/29
1.3K0
Kotlin Multiplatform Mobile 进入 Beta 测试
如果要使用 Bazel ,我会考虑什么?
{Fast, Correct} - Choose two Build and test software of any size, quickly and reliably
donghui
2019/10/30
1.5K0
如果要使用 Bazel ,我会考虑什么?
谷歌的Bazel构建工具
在当今的软件开发世界中,构建工具的选择对于提高开发效率、维护代码质量以及提升团队协作能力都至关重要。谷歌作为全球技术巨头,为了解决大规模代码构建和测试的挑战,开发了一款名为Bazel的构建工具。Bazel具有强大的功能和灵活性,已成为开源社区中的明星工具。本文将深入探讨谷歌的Bazel构建工具及其在软件开发中的应用。
DevOps持续交付
2023/12/13
6260
谷歌的Bazel构建工具
我的自动化构建之路之 Jenkins+Fastlane+Github内网测试
可能看到这一篇文章很多人认为 Jenkins就可以实现自动化打包,并且 Fastlane配置 完毕之后打包更加的轻松。干嘛还搞在一起,这不是重复了吗。
君赏
2018/09/07
1.7K0
🧭 React Native 版本升级指南
React Native 作为一款跨端框架,有一个最让人头疼的问题,那就是版本更新。尤其是遇到大版本更新,JavaScript、iOS 和 Android 三端的配置构建文件都有非常大的变动,有时候三者的配置文件又互相耦合在一起,往往牵一发而动全身。
卤代烃
2022/02/23
4.8K0
🧭 React Native 版本升级指南
手把手教你利用Jenkins持续集成iOS项目
众所周知,现在App的竞争已经到了用户体验为王,质量为上的白热化阶段。用户们都是很挑剔的。如果一个公司的推广团队好不容易砸了重金推广了一个APP,好不容易有了一些用户,由于一次线上的bug导致一批的用户在使用中纷纷出现闪退bug,轻则,很可能前期推广砸的钱都白费了,重则,口碑不好,未来也提升不起用户量来了。静下心来分析一下问题的原因,无外乎就是质量没有过关就上线了。除去主观的一些因素,很大部分的客观因素我觉得可以被我们防范的。根据大神们提出的一套开发规范建议,CI + FDD,就可以帮助我们极大程度的解决客观因素。本文接下来主要讨论 Continuous Integration 持续集成(简称CI)
一缕殇流化隐半边冰霜
2018/08/29
1.6K0
手把手教你利用Jenkins持续集成iOS项目
手把手教你利用Jenkins持续集成iOS项目
前言 众所周知,现在App的竞争已经到了用户体验为王,质量为上的白热化阶段。用户们都是很挑剔的。如果一个公司的推广团队好不容易砸了重金推广了一个APP,好不容易有了一些用户,由于一次线上的bug导致一批的用户在使用中纷纷出现闪退bug,轻则,很可能前期推广砸的钱都白费了,重则,口碑不好,未来也提升不起用户量来了。静下心来分析一下问题的原因,无外乎就是质量没有过关就上线了。 除去主观的一些因素,很大部分的客观因素我觉得可以被我们防范的。根据大神们提出的一套开发规范建议,CI + FDD,就可以帮助我们极大程
DevOps时代
2018/06/22
2.1K0
[Bazel]自定义工具链
本文会讲述 Bazel 自定义工具链的两种方式,Platform 和 Non-Platform 方式。会存在这两种方式的原因是 Bazel 的历史问题。例如,C++ 相关规则使用 --cpu 和 --crosstool_top 来设置一个构建目标 CPU 和 C++ 工具链,这样就可以实现选择不同的工具链构建 C++ 项目。但是这都不能正确地表达出“平台”特征。使用这种方式不可避免地导致出现了笨拙且不准确的构建 APIs。这其中导致了对 Java 工具链基本没有涉及,Java 工具链就发展了他们自己的独立接口 --java_toolchain。因此非平台方式(Non-Platform)的自定义工具链实现并没有统一的 APIs 来规范不同语言的跨平台构建。而 Bazel 的目标是在大型、混合语言、多平台项目中脱颖而出。这就要求对这些概念有更原则的支持,包括清晰的 APIs,这些 API 绑定而不是分散语言和项目。这就是新平台(platform)和工具链(toolchain) APIs 所实现的内容。
别打名名
2020/08/11
4.9K8
Spotify Portal for Backstage 简化平台工程
创建 Backstage 的路径涉及尊重 Spotify 的协作文化和开发人员自主权。其新门户旨在将这种精神带给所有 Backstage 用户。
云云众生s
2024/05/02
1720
Spotify Portal for Backstage 简化平台工程
占坑!利用 JenKins 持续集成 iOS 项目时遇到的问题
持续集成(Continuous Integration,简称CI)是一种软件开发实践:许多团队频繁地集成他们的工作,每位成员通常进行日常集成,进而每天会有多种集成。
DevOps时代
2018/08/01
2.8K0
占坑!利用 JenKins 持续集成 iOS 项目时遇到的问题
程序员面试闪充--Cocoapods的详解
在开发iOS应用时,会经常使用到很多第三方开源类库,比如JSONKit,AFNetWorking等等。可能某个类库又用到其他类库,所以要使用它,必须得另外下载其他类库,而其他类库又用到其他类库,“子子孙孙无穷尽也”。 一、介绍 CocoaPods是开发OSX和iOS应用程序的一个第三方库的依赖管理工具。利用CocoaPods,可以定义自己的依赖关系(称作pods),并且随着时间的变化,以及在整个开发环境中对第三方库的版本管理非常方便。 优点:快速查找新的第三方库。替换旧的框架(缩短开发周期和提升软件质量)/
谦谦君子修罗刀
2018/05/02
2.3K0
程序员面试闪充--Cocoapods的详解
【Unity开发小技巧】打包IOS版本须知流程(移动)
Unity是个开放性的平台,打包时也可以选择多种打包类型,几乎包含了所有的平台,目前主流Android,iOS平台,Android平台可以直接使用Unity自行打包,但iOS平台需要借助Mac电脑进行打包,本博客就iOS打包进行一个简单的说明,从开发到上线AppStore的所有流程。
全栈程序员站长
2022/09/07
6K0
【Unity开发小技巧】打包IOS版本须知流程(移动)
Flutter 搭建 iOS 命令行服务打包发布全保姆式流程
在以前的 《 Android 和 iOS 打包提交审核指南》 里介绍了 Flutter 下打包 Android 和 iOS 的指南,不过这部分内容主要介绍的是如何在本地打包发布流程。
GSYTech
2021/04/23
3.5K1
Flutter 搭建 iOS 命令行服务打包发布全保姆式流程
Travis CI 教程:入门
在这个 Travis CI 教程中,学习如何设置流行的持续集成服务,并与 GitHub 集成,以便自动运行测试。
iOSDevLog
2019/05/07
5.7K0
Travis CI 教程:入门
iOS应用构建与部署小结
上篇文章介绍了Objective-C的基本概念,本文就来接着看如何创建我们的第一个简单iOS应用, 本着简单可复现的方式,我们会以尽可能小的成本来构建并在真机运行iOS应用。 也就是说, 不用越狱, 也无需开发者账号。当然,一台iPhone手机还是需要的,最好还有一台Mac。
evilpan
2023/02/12
2.2K0
iOS应用构建与部署小结
推荐阅读
相关推荐
Airbnb从Buck 迁移到 Bazel,大幅改善开发者体验
更多 >
目录
  • 介绍
    • 带有虚拟线程的 Spring Boot
  • 测试环境及软件版本
    • 负载测试和 JWT
    • MySQL 数据库架构
  • 代码
    • SpringBoot(物理线程)
    • Springboot(虚拟线程)
    • SpringBoot(webflux)
  • 结果
  • 分析
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档