java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring Boot  WebFlux使用

Spring Boot + WebFlux 全面使用实践指南

作者:谁在黄金彼岸

SpringWebFlux是Spring Framework 5+提供的响应式Web框架,性能与配置优化包括调整Netty参数、启用背压控制和监控指标,常见陷阱与最佳实践,本文给大家介绍Spring Boot+WebFlux全面使用指南,感兴趣的朋友跟随小编一起看看吧

一、什么是 Spring WebFlux?

✅ WebFlux ≠ WebMVC 替代品,而是 互补技术栈,适用于不同场景。

二、何时使用 WebFlux?

场景推荐
高并发 I/O 密集型(API 网关、实时推送、IoT)✅ 强烈推荐
全链路响应式技术栈(R2DBC + WebClient + Reactive MQ)
低并发传统业务系统(后台管理、简单 CRUD)❌ 用 WebMVC 更简单
强事务性/复杂 SQL(需 Hibernate/JPA)❌ 不适合

三、快速入门:创建 WebFlux 项目

1. 使用 Spring Initializr(https://start.spring.io/)

选择:

2. 手动添加依赖(Maven)

<dependencies>
    <!-- WebFlux 核心 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <!-- 响应式数据库(以 MariaDB 为例) -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-r2dbc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.mariadb</groupId>
        <artifactId>r2dbc-mariadb</artifactId>
        <version>1.1.5</version>
    </dependency>
    <dependency>
        <groupId>org.mariadb</groupId>
        <artifactId>mariadb-java-client</artifactId>
        <scope>runtime</scope>
    </dependency>
    <!-- 测试 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.projectreactor</groupId>
        <artifactId>reactor-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

3. 启动类(无需特殊注解)

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

🔍 启动日志将显示:Netty started on port 8080

四、两种编程模型

A. 注解式(Annotation-based)— 类似 Spring MVC

@RestController
@RequestMapping("/users")
public class UserController {
    @Autowired
    private UserRepository userRepository;
    // 返回单个对象
    @GetMapping("/{id}")
    public Mono<User> getUser(@PathVariable String id) {
        return userRepository.findById(id);
    }
    // 返回列表流
    @GetMapping
    public Flux<User> getAllUsers() {
        return userRepository.findAll();
    }
    // 创建用户
    @PostMapping
    public Mono<User> createUser(@RequestBody User user) {
        return userRepository.save(user);
    }
    // SSE:服务器推送事件
    @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> streamEvents() {
        return Flux.interval(Duration.ofSeconds(1))
                   .map(seq -> "Event #" + seq);
    }
}

✅ 优点:学习成本低,与 MVC 风格一致
⚠️ 注意:方法必须返回 MonoFlux

B. 函数式(Functional)— 纯函数式路由

1. 定义 Handler

@Component
public class UserHandler {
    private final UserRepository userRepository;
    public UserHandler(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    public Mono<ServerResponse> getUser(ServerRequest request) {
        String id = request.pathVariable("id");
        Mono<User> user = userRepository.findById(id);
        return user
            .flatMap(u -> ServerResponse.ok().bodyValue(u))
            .switchIfEmpty(ServerResponse.notFound().build());
    }
    public Mono<ServerResponse> getAllUsers(ServerRequest request) {
        Flux<User> users = userRepository.findAll();
        return ServerResponse.ok().body(users, User.class);
    }
}

2. 定义 RouterFunction(替代 @RequestMapping)

@Configuration
public class UserRouter {
    @Bean
    public RouterFunction<ServerResponse> userRoutes(UserHandler handler) {
        return route()
            .GET("/users/{id}", handler::getUser)
            .GET("/users", handler::getAllUsers)
            .build();
    }
}

✅ 优点:更符合响应式思想,易于单元测试,无反射开销
💡 适合构建轻量级、高内聚的 API

五、响应式数据访问(R2DBC)

1. 实体类

@Table("users")
public class User {
    @Id
    private Long id;
    private String name;
    private String email;
    // constructors, getters, setters
}

2. Repository

public interface UserRepository extends ReactiveCrudRepository<User, Long> {
    Flux<User> findByEmail(String email);
}

3. application.yml 配置

spring:
  r2dbc:
    url: r2dbc:mariadb://localhost:3306/mydb
    username: root
    password: password

支持连接池(需引入 io.r2dbc:r2dbc-pool

六、响应式 HTTP 客户端:WebClient

替代 RestTemplate,非阻塞调用外部服务:

@Service
public class ExternalServiceClient {
    private final WebClient webClient;
    public ExternalServiceClient() {
        this.webClient = WebClient.builder()
            .baseUrl("https://api.example.com")
            .build();
    }
    public Mono<UserProfile> fetchProfile(String userId) {
        return webClient.get()
            .uri("/profiles/{id}", userId)
            .retrieve()
            .bodyToMono(UserProfile.class)
            .onErrorResume(e -> Mono.empty()); // 错误降级
    }
}

七、全局异常处理

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(UserNotFoundException.class)
    public Mono<ResponseEntity<String>> handleUserNotFound(Exception ex) {
        return Mono.just(ResponseEntity
            .status(HttpStatus.NOT_FOUND)
            .body("User not found"));
    }
    @ExceptionHandler(Exception.class)
    public Mono<ResponseEntity<String>> handleGeneral(Exception ex) {
        return Mono.just(ResponseEntity
            .status(HttpStatus.INTERNAL_SERVER_ERROR)
            .body("Internal error"));
    }
}

也可使用函数式方式注册 WebExceptionHandler

八、测试:WebTestClient

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UserControllerTest {
    @Autowired
    private WebTestClient webClient;
    @Test
    void shouldGetUser() {
        webClient.get().uri("/users/1")
            .exchange()
            .expectStatus().isOk()
            .expectBody(User.class)
            .value(user -> assertThat(user.getName()).isEqualTo("Alice"));
    }
}

九、性能与配置优化

1. 调整 Netty 参数(application.yml)

server:
  netty:
    connection-timeout: 30s
    max-in-memory-size: 10MB  # 防止 OOM

2. 启用背压控制

Flux.range(1, 1000)
    .limitRate(100) // 控制上游发射速率
    .onBackpressureBuffer(500); // 缓冲溢出数据

3. 监控与指标

集成 Micrometer + Prometheus,监控 reactor.netty.connection.provider.active.connections 等指标。

十、常见陷阱与最佳实践

问题建议
在 WebFlux 中调用 JDBC / Thread.sleep()❌ 会阻塞 EventLoop,导致服务不可用
混合使用 WebMVC 和 WebFlux⚠️ 可以共存,但不要在同一个 Controller 中混用
忽略背压⚠️ 大流量下可能 OOM,务必使用 limitRate / onBackpressureXXX
过度使用 block()❌ 破坏响应式模型,仅用于测试或边界转换

✅ 总结:WebFlux 开发 Checklist

通过以上指南,你已掌握 Spring Boot + WebFlux 的完整开发能力。记住:WebFlux 的价值不在于“更快”,而在于“更高吞吐、更低资源消耗”。在合适的场景下使用它,将显著提升系统伸缩性。

官方文档:

到此这篇关于Spring Boot + WebFlux 全面使用实践指南的文章就介绍到这了,更多相关Spring Boot WebFlux使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文