掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
早上看到一篇關(guān)于Spring Boot虛擬線程和Webflux性能對(duì)比的文章,覺得還不錯(cuò)。內(nèi)容較長(zhǎng),抓重點(diǎn)給大家介紹一下這篇文章的核心內(nèi)容,方便大家快速閱讀。

10年積累的網(wǎng)站設(shè)計(jì)制作、網(wǎng)站建設(shè)經(jīng)驗(yàn),可以快速應(yīng)對(duì)客戶對(duì)網(wǎng)站的新想法和需求。提供各種問題對(duì)應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先網(wǎng)站制作后付款的網(wǎng)站建設(shè)流程,更有鼓樓免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
作者采用了一個(gè)盡可能貼近現(xiàn)實(shí)操作的場(chǎng)景:
這里要對(duì)比的兩個(gè)核心技術(shù)點(diǎn)是:
不論是Webflux還是虛擬線程,這兩個(gè)都是為了提供程序的高并發(fā)能力而生,那么誰(shuí)更勝一籌呢?下面一起看看具體的測(cè)試。
運(yùn)行環(huán)境與工具
數(shù)據(jù)準(zhǔn)備
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)application.properties配置文件:
server.port=3000
spring.datasource.url= jdbc:mysql://localhost:3306/testdb?useSSL=false
spring.datasource.username= testuser
spring.datasource.password= testpwd
spring.jpa.hibernate.ddl-auto= update
spring.datasource.driver-class-name=com.mysql.cj.jdbc.DriverUser實(shí)體類(為了讓文章讓簡(jiǎn)潔一些,這里DD省略了getter和setter):
@Entity
@Table(name = "users")
public class User {
@Id
private String email;
private String first;
private String last;
private String city;
private String county;
private int age;
}應(yīng)用主類:
@SpringBootApplication
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
@Bean
public TomcatProtocolHandlerCustomizer> protocolHandlerVirtualThreadExecutorCustomizer() {
return protocolHandler -> {
protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
};
}
}提供CRUD操作的UserRepository:
import org.springframework.data.repository.CrudRepository;
import com.example.demo.User;
public interface UserRepository extends CrudRepository {
} 提供API接口的UserController類:
@RestController
public class 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 = userRepository.findById((String)claims.get("email"));
return user.get();
}
} application.properties配置文件:
server.port=3000
spring.r2dbc.url=r2dbc:mysql://localhost:3306/testdb
spring.r2dbc.username=dbser
spring.r2dbc.password=dbpwdUser實(shí)體(這里DD也省略了構(gòu)造函數(shù)、getter和setter):
public class User {
@Id
private String email;
private String first;
private String last;
private String city;
private String county;
private int age;
// 省略了構(gòu)造函數(shù)、getter、setter
}應(yīng)用主類:
@EnableWebFlux
@SpringBootApplication
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}提供CRUD操作的UserRepository:
public interface UserRepository extends R2dbcRepository {
} 提供根據(jù)id查用戶的業(yè)務(wù)類UserService:
@Service
public class UserService {
@Autowired
UserRepository userRepository;
public Mono findById(String id) {
return userRepository.findById(id);
}
} 提供API接口的UserController類:
@RestController
@RequestMapping("/")
public class UserController {
@Autowired
UserService userService;
private SignatureAlgorithm sa = SignatureAlgorithm.HS256;
private String jwtSecret = System.getenv("JWT_SECRET");
@GetMapping("/")
@ResponseStatus(HttpStatus.OK)
public Mono 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"));
}
} 接下來是重頭戲了,作者對(duì)兩個(gè)技術(shù)方案都做了500w個(gè)請(qǐng)求的測(cè)試,評(píng)估的不同并發(fā)連接級(jí)別包含:50、100、300。
具體結(jié)果如下三張圖:
50并發(fā)連接
100并發(fā)連接
300并發(fā)連接
最后,作者得出結(jié)論:Spring Boot Webflux要更優(yōu)于帶虛擬線程的Spring Boot。
似乎引入了虛擬線程還不如已經(jīng)在用的Webflux?不知道大家是否有做過相關(guān)調(diào)研呢?如果有的話,歡迎在留言區(qū)一起聊聊~我們創(chuàng)建了一個(gè)高質(zhì)量的技術(shù)交流群,與優(yōu)秀的人在一起,自己也會(huì)優(yōu)秀起來,趕緊點(diǎn)擊加群,享受一起成長(zhǎng)的快樂。

我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流