Spring WebFlux 2025 构建高性能非阻塞API

在现代分布式系统中,高并发场景越来越普遍,传统的阻塞式IO模型已难以满足需求。Spring WebFlux作为Spring生态中的响应式编程解决方案,经过多年发展已成为构建高性能非阻塞API的首选框架。本文将基于2025年最新技术栈,提供一套完整的Spring WebFlux实操指南。

技术栈准备

我们将使用以下最新技术组件:

  • Spring Boot 3.3.0(包含Spring WebFlux 6.2.0)
  • Reactor Core 3.6.0(响应式编程基础)
  • Spring Data R2DBC 3.3.0(关系型数据库响应式访问)
  • H2 Database 2.3.0(嵌入式数据库,方便演示)
  • Project Reactor Addons 3.6.0(响应式工具类)
  • Java 21(提供虚拟线程等新特性)

环境搭建

首先创建一个Spring Boot项目,推荐使用Spring Initializr(https://start.spring.io/),选择以下依赖:

  • Spring Reactive Web
  • Spring Data R2DBC
  • H2 Database
  • Lombok(可选,简化代码)

Maven依赖文件(pom.xml)关键部分如下:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.3.0</version>
    <relativePath/>
</parent>

<dependencies>
    <!-- Spring WebFlux 核心依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>

    <!-- 响应式数据库支持 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-r2dbc</artifactId>
    </dependency>

    <!-- H2 数据库 -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>

    <!-- 响应式工具类 -->
    <dependency>
        <groupId>io.projectreactor.addons</groupId>
        <artifactId>reactor-extra</artifactId>
    </dependency>

    <!-- Lombok 简化代码 -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

    <!-- 测试依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>io.projectreactor</groupId>
        <artifactId>reactor-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
 
 

项目结构设计

我们将构建一个简单的用户管理API,采用分层架构:

com.example.reactive
├── config          # 配置类
├── controller      # 控制器层
├── handler         # 函数式处理器
├── router          # 路由配置
├── model           # 数据模型
├── repository      # 数据访问层
└── service         # 业务逻辑层
 
 

核心代码实现

1. 数据模型

首先创建用户实体类:

package com.example.reactive.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Table("users")
public class User {
   
    @Id
    private Long id;
    private String username;
    private String email;
    private String fullName;
    private boolean active;
}
 
 

2. 数据库配置

创建R2DBC配置类,配置数据库连接:

package com.example.reactive.config;

import io.r2dbc.h2.H2ConnectionFactory;
import io.r2dbc.spi.ConnectionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration;
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;

@Configuration
@EnableR2dbcRepositories(basePackages = "com.example.reactive.repository")
public class R2DBCConfig extends AbstractR2dbcConfiguration {
   

    @Bean
    @Override
    public ConnectionFactory connectionFactory() {
   
        // 使用内存模式的H2数据库
        return H2ConnectionFactory.inMemory("testdb");
    }
}
 
 

创建数据库初始化脚本(src/main/resources/schema.sql):

CREATE TABLE IF NOT EXISTS users (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL UNIQUE,
    email VARCHAR(100) NOT NULL UNIQUE,
    full_name VARCHAR(100) NOT NULL,
    active BOOLEAN DEFAULT TRUE
);
 
 

3. 数据访问层

创建响应式Repository接口:

package com.example.reactive.repository;

import com.example.reactive.model.User;
import org.springframework.data.r2dbc.repository.R2dbcRepository;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Mono;

@Repository
public interface UserRepository extends R2dbcRepository<User, Long> {
   
    // 根据用户名查询用户
    Mono<User> findByUsername(String username);

    // 根据邮箱查询用户
    Mono<User> findByEmail(String email);
}
 
 

4. 业务逻辑层

创建服务接口和实现类:

package com.example.reactive.service;

import com.example.reactive.model.User;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public interface UserService {
   
    Flux<User> findAll();
    Mono<User> findById(Long id);
    Mono<User> save(User user);
    Mono<User> update(Long id, User user);
    Mono<Void> deleteById(Long id);
    Mono<User> findByUsername(String username);
}
 
 

实现类:

package com.example.reactive.service;

import com.example.reactive.model.User;
import com.example.reactive.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
   

    private final UserRepository userRepository;

    @Override
    public Flux<User> findAll() {
   
        return userRepository.findAll();
    }

    @Override
    public Mono<User> findById(Long id) {
   
        return userRepository.findById(id)
                .switchIfEmpty(Mono.error(new RuntimeException("User not found with id: " + id)));
    }

    @Override
    public Mono<User> save(User user) {
   
        // 可以在这里添加业务验证逻辑
        return userRepository.save(user);
    }

    @Override
    public Mono<User> update(Long id, User user) {
   
        return userRepository.findById(id)
                .flatMap(existingUser -> {
   
                    existingUser.setUsername(user.getUsername());
                    existingUser.setEmail(user.getEmail());
                    existingUser.setFullName(user.getFullName());
                    existingUser.setActive(user.isActive());
                    return userRepository.save(existingUser);
                })
                .switchIfEmpty(Mono.error(new RuntimeException("User not found with id: " + id)));
    }

    @Override
    public Mono<Void> deleteById(Long id) {
   
        return userRepository.existsById(id)
                .flatMap(exists -> {
   
                    if (exists) {
   
                        return userRepository.deleteById(id);
                    } else {
   
                        return Mono.error(new RuntimeException("User not found with id: " + id));
                    }
                });
    }

    @Override
    public Mono<User> findByUsername(String username) {
   
        return userRepository.findByUsername(username)
                .switchIfEmpty(Mono.error(new RuntimeException("User not found with username: " + username)));
    }
}
 
 

5. API实现(注解式控制器)

创建基于注解的REST控制器:

package com.example.reactive.controller;

import com.example.reactive.model.User;
import com.example.reactive.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
   

    private final UserService userService;

    @GetMapping
    public Flux<User> getAllUsers() {
   
        return userService.findAll();
    }

    @GetMapping("/{id}")
    public Mono<ResponseEntity<User>> getUserById(@PathVariable Long id) {
   
        return userService.findById(id)
                .map(ResponseEntity::ok)
                .defaultIfEmpty(ResponseEntity.notFound().build());
    }

    @GetMapping("/username/{username}")
    public Mono<ResponseEntity<User>> getUserByUsername(@PathVariable String username) {
   
        return userService.findByUsername(username)
                .map(ResponseEntity::ok)
                .defaultIfEmpty(ResponseEntity.notFound().build());
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public Mono<User> createUser(@RequestBody User user) {
   
        return userService.save(user);
    }

    @PutMapping("/{id}")
    public Mono<ResponseEntity<User>> updateUser(@PathVariable Long id, @RequestBody User user) {
   
        return userService.update(id, user)
                .map(ResponseEntity::ok)
                .defaultIfEmpty(ResponseEntity.notFound().build());
    }

    @DeleteMapping("/{id}")
    public Mono<ResponseEntity<Void>> deleteUser(@PathVariable Long id) {
   
        return userService.deleteById(id)
                .then(Mono.just(ResponseEntity.noContent().build()))
                .onErrorResume(e -> Mono.just(ResponseEntity.notFound().build()));
    }

    // 全局异常处理
    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity<String> handleRuntimeException(RuntimeException ex) {
   
        return ResponseEntity
                .status(HttpStatus.NOT_FOUND)
                .body(ex.getMessage());
    }
}
 
 

6. API实现(函数式端点)

除了注解式控制器,Spring WebFlux还支持函数式编程模型。下面实现一套相同功能的函数式端点:

首先创建处理器:

package com.example.reactive.handler;

import com.example.reactive.model.User;
import com.example.reactive.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

@Component
@RequiredArgsConstructor
public class UserHandler {
   

    private final UserService userService;

    // 获取所有用户
    public Mono<ServerResponse> getAllUsers(ServerRequest request) {
   
        return ServerResponse.ok()
                .contentType(MediaType.APPLICATION_JSON)
                .body(userService.findAll(), User.class);
    }

    // 根据ID获取用户
    public Mono<ServerResponse> getUserById(ServerRequest request) {
   
        Long id = Long.parseLong(request.pathVariable("id"));

        return userService.findById(id)
                .flatMap(user -> ServerResponse.ok()
                        .contentType(MediaType.APPLICATION_JSON)
                        .bodyValue(user))
                .switchIfEmpty(ServerResponse.notFound().build());
    }

    // 创建用户
    public Mono<ServerResponse> createUser(ServerRequest request) {
   
        Mono<User> userMono = request.bodyToMono(User.class);

        return userMono
                .flatMap(user -> userService.save(user))
                .flatMap(savedUser -> ServerResponse.status(HttpStatus.CREATED)
                        .contentType(MediaType.APPLICATION_JSON)
                        .bodyValue(savedUser));
    }

    // 更新用户
    public Mono<ServerResponse> updateUser(ServerRequest request) {
   
        Long id = Long.parseLong(request.pathVariable("id"));
        Mono<User> userMono = request.bodyToMono(User.class);

        return userMono
                .flatMap(user -> userService.update(id, user))
                .flatMap(updatedUser -> ServerResponse.ok()
                        .contentType(MediaType.APPLICATION_JSON)
                        .bodyValue(updatedUser))
                .switchIfEmpty(ServerResponse.notFound().build());
    }

    // 删除用户
    public Mono<ServerResponse> deleteUser(ServerRequest request) {
   
        Long id = Long.parseLong(request.pathVariable("id"));

        return userService.deleteById(id)
                .then(ServerResponse.noContent().build())
                .onErrorResume(e -> ServerResponse.notFound().build());
    }
}
 
 

然后创建路由配置:

package com.example.reactive.router;

import com.example.reactive.handler.UserHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;

import static org.springframework.web.reactive.function.server.RequestPredicates.*;

@Configuration
public class UserRouter {
   

    @Bean
    public RouterFunction<ServerResponse> userRoutes(UserHandler userHandler) {
   
        return RouterFunctions
                .route(GET("/func/users"), userHandler::getAllUsers)
                .andRoute(GET("/func/users/{id}"), userHandler::getUserById)
                .andRoute(POST("/func/users"), userHandler::createUser)
                .andRoute(PUT("/func/users/{id}"), userHandler::updateUser)
                .andRoute(DELETE("/func/users/{id}"), userHandler::deleteUser);
    }
}
 
 

响应式客户端使用

Spring WebFlux提供了WebClient作为响应式HTTP客户端,下面演示如何使用它:

package com.example.reactive.service;

import com.example.reactive.model.User;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Component
@RequiredArgsConstructor
public class UserWebClient {
   

    private final WebClient webClient;

    // 构造函数注入WebClient
    public UserWebClient() {
   
        this.webClient = WebClient.create("http://localhost:8080");
    }

    // 获取所有用户
    public Flux<User> getAllUsers() {
   
        return webClient.get()
                .uri("/api/users")
                .retrieve()
                .bodyToFlux(User.class);
    }

    // 根据ID获取用户
    public Mono<User> getUserById(Long id) {
   
        return webClient.get()
                .uri("/api/users/{id}", id)
                .retrieve()
                .bodyToMono(User.class);
    }

    // 创建用户
    public Mono<User> createUser(User user) {
   
        return webClient.post()
                .uri("/api/users")
                .bodyValue(user)
                .retrieve()
                .bodyToMono(User.class);
    }
}
 
 

测试响应式API

使用JUnit 5和Reactor Test进行测试:

package com.example.reactive.controller;

import com.example.reactive.model.User;
import com.example.reactive.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

@WebFluxTest(UserController.class)
public class UserControllerTest {
   

    @Autowired
    private WebTestClient webTestClient;

    @MockBean
    private UserService userService;

    @Test
    public void testGetAllUsers() {
   
        User user1 = new User(1L, "user1", "user1@example.com", "User One", true);
        User user2 = new User(2L, "user2", "user2@example.com", "User Two", true);

        when(userService.findAll()).thenReturn(Flux.just(user1, user2));

        webTestClient.get().uri("/api/users")
                .accept(MediaType.APPLICATION_JSON)
                .exchange()
                .expectStatus().isOk()
                .expectHeader().contentType(MediaType.APPLICATION_JSON)
                .expectBodyList(User.class)
                .hasSize(2)
                .contains(user1, user2);
    }

    @Test
    public void testCreateUser() {
   
        User user = new User(null, "newuser", "newuser@example.com", "New User", true);
        User savedUser = new User(3L, "newuser", "newuser@example.com", "New User", true);

        when(userService.save(any(User.class))).thenReturn(Mono.just(savedUser));

        webTestClient.post().uri("/api/users")
                .contentType(MediaType.APPLICATION_JSON)
                .bodyValue(user)
                .exchange()
                .expectStatus().isCreated()
                .expectBody(User.class)
                .isEqualTo(savedUser);
    }
}
 
 

性能优化建议

  1. 背压管理:利用Reactor的背压机制,控制数据流速度,防止下游组件被压垮

  2. 连接池配置:优化R2DBC连接池和WebClient连接池

    @Bean
    public ConnectionFactory connectionFactory() {
         
        H2ConnectionConfiguration config = H2ConnectionConfiguration.builder()
                .url("r2dbc:h2:mem:testdb")
                .username("sa")
                .password("")
                .build();
    
        return ConnectionPoolConfiguration.builder()
                .connectionFactory(new H2ConnectionFactory(config))
                .maxSize(10)
                .build();
    }
     
     
  3. 数据批量处理:使用Flux.buffer()Flux.window()进行批量操作

  4. 缓存热点数据:结合cache()操作符缓存频繁访问的数据

  5. 监控与指标:集成Micrometer监控响应式流的性能指标

总结

Spring WebFlux提供了构建非阻塞、高性能API的完整解决方案。通过本文的实操指南,你已经了解了如何使用最新的Spring WebFlux技术栈构建响应式API,包括:

  • 环境搭建与配置
  • 响应式数据访问
  • 两种API实现方式(注解式和函数式)
  • 响应式客户端使用
  • 测试与性能优化

在实际项目中,应根据具体场景选择合适的编程模型,并充分利用响应式编程的特性来提升系统的并发处理能力和资源利用率。随着Java和Spring生态的不断发展,响应式编程将会在高并发场景中发挥越来越重要的作用。

posted @ 2025-10-27 16:20  kiyte  阅读(28)  评论(0)    收藏  举报