news 2026/7/3 20:24:07

Spring WebFlux 学习

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring WebFlux 学习

Spring WebFlux 是 Spring Framework 5 引入的响应式(Reactive)Web 框架,用于构建非阻塞、异步、事件驱动的 Web 应用程序。它与传统的基于 Servlet 的 Spring MVC 并行存在,但底层架构完全不同。

一、WebFlux 核心概念

1.1 什么是响应式编程?

  • 数据流:将数据视为随时间变化的流

  • 非阻塞:不等待操作完成,继续执行其他任务

  • 背压:消费者控制生产者速度,防止数据积压

1.2 与传统 Spring MVC 对比

特性Spring MVCSpring WebFlux
编程模型命令式、同步响应式、异步
并发模型线程池(每个请求一个线程)事件循环(少量线程处理大量请求)
阻塞性可能阻塞(如DB查询)完全非阻塞
适用场景传统应用、简单CRUD高并发、实时应用、流处理

二、WebFlux 核心组件

2.1 Reactive Streams API

Publisher<T> // 发布者 Subscriber<T> // 订阅者 Subscription // 订阅关系 Processor<T,R> // 处理器

2.2 Reactor 核心类

// Mono: 0-1个元素的异步序列 Mono<String> mono = Mono.just("Hello"); Mono<Void> monoEmpty = Mono.empty(); Mono<String> monoError = Mono.error(new RuntimeException()); // Flux: 0-N个元素的异步序列 Flux<String> flux = Flux.just("A", "B", "C"); Flux<Integer> fluxRange = Flux.range(1, 10); Flux<Long> fluxInterval = Flux.interval(Duration.ofSeconds(1));

三、WebFlux 开发方式

3.1 注解式控制器(类似 MVC)

@RestController @RequestMapping("/api") public class UserController { @GetMapping("/users/{id}") public Mono<User> getUser(@PathVariable String id) { return userRepository.findById(id); } @GetMapping("/users") public Flux<User> getAllUsers() { return userRepository.findAll(); } @PostMapping("/users") public Mono<User> createUser(@RequestBody User user) { return userRepository.save(user); } // SSE(服务器发送事件) @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<User> streamUsers() { return userRepository.findAll().delayElements(Duration.ofSeconds(1)); } }

3.2 函数式端点(Router Functions)

@Configuration public class RouterConfig { @Bean public RouterFunction<ServerResponse> routes(UserHandler userHandler) { return RouterFunctions.route() .GET("/api/users", userHandler::getAllUsers) .GET("/api/users/{id}", userHandler::getUser) .POST("/api/users", userHandler::createUser) .build(); } } @Component public class UserHandler { public Mono<ServerResponse> getAllUsers(ServerRequest request) { Flux<User> users = userRepository.findAll(); return ServerResponse.ok() .contentType(MediaType.APPLICATION_JSON) .body(users, User.class); } 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()); } }

四、WebFlux 与数据层集成

4.1 Reactive MongoDB

@Document public class Product { @Id private String id; private String name; private Double price; } public interface ProductRepository extends ReactiveMongoRepository<Product, String> { Flux<Product> findByPriceGreaterThan(Double price); @Query("{ 'name': { $regex: ?0 } }") Flux<Product> findByNameRegex(String regex); }

4.2 Reactive Redis

@Configuration public class RedisConfig { @Bean public ReactiveRedisTemplate<String, Object> reactiveRedisTemplate( ReactiveRedisConnectionFactory factory) { RedisSerializationContext<String, Object> context = RedisSerializationContext .newSerializationContext(new StringRedisSerializer()) .hashKey(new StringRedisSerializer()) .hashValue(new GenericJackson2JsonRedisSerializer()) .build(); return new ReactiveRedisTemplate<>(factory, context); } } @Service public class CacheService { @Autowired private ReactiveRedisTemplate<String, Object> redisTemplate; public Mono<Object> get(String key) { return redisTemplate.opsForValue().get(key); } public Mono<Boolean> set(String key, Object value, Duration timeout) { return redisTemplate.opsForValue() .set(key, value, timeout); } }

五、WebFlux 配置

5.1 应用配置

# application.yml spring: webflux: base-path: /api hidden-method: filter: enabled: true codec: max-in-memory-size: 10MB thymeleaf: reactive: max-chunk-size: 8192

Maven 依赖(Spring Boot)

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency>

5.2 服务器配置

@Configuration public class ServerConfig { @Bean public WebFluxConfigurer webFluxConfigurer() { return new WebFluxConfigurer() { @Override public void configureHttpMessageCodecs( ServerCodecConfigurer configurer) { configurer.defaultCodecs() .maxInMemorySize(10 * 1024 * 1024); } @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("*"); } }; } }

六、响应式 WebClient

@Service public class ApiClientService { private final WebClient webClient; public ApiClientService(WebClient.Builder builder) { this.webClient = builder .baseUrl("https://api.chengxuyuanshitang.com") .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .build(); } public Mono<User> fetchUser(String userId) { return webClient.get() .uri("/users/{id}", userId) .retrieve() .bodyToMono(User.class) .timeout(Duration.ofSeconds(5)) .retryWhen(Retry.fixedDelay(3, Duration.ofSeconds(1))); } public Flux<Product> streamProducts() { return webClient.get() .uri("/products/stream") .accept(MediaType.TEXT_EVENT_STREAM) .retrieve() .bodyToFlux(Product.class); } }

七、错误处理

@RestControllerAdvice public class GlobalErrorHandler { @ExceptionHandler(ResourceNotFoundException.class) public Mono<ResponseEntity<ErrorResponse>> handleNotFound( ResourceNotFoundException ex) { ErrorResponse error = new ErrorResponse( "NOT_FOUND", ex.getMessage() ); return Mono.just( ResponseEntity.status(HttpStatus.NOT_FOUND) .body(error) ); } // 响应式异常处理 @ExceptionHandler(WebExchangeBindException.class) public Mono<ResponseEntity<ErrorResponse>> handleValidationException( WebExchangeBindException ex) { List<String> errors = ex.getFieldErrors() .stream() .map(fe -> fe.getField() + ": " + fe.getDefaultMessage()) .collect(Collectors.toList()); ErrorResponse error = new ErrorResponse( "VALIDATION_ERROR", errors.toString() ); return Mono.just( ResponseEntity.badRequest().body(error) ); } }

八、WebFlux 测试

@SpringBootTest @AutoConfigureWebTestClient class UserControllerTest { @Autowired private WebTestClient webTestClient; @Test void testGetUser() { webTestClient.get() .uri("/api/users/1") .exchange() .expectStatus().isOk() .expectBody() .jsonPath("$.name").isEqualTo("zhangsanfeng"); } @Test void testStreamUsers() { webTestClient.get() .uri("/api/users/stream") .accept(MediaType.TEXT_EVENT_STREAM) .exchange() .expectStatus().isOk() .expectHeader().contentType(MediaType.TEXT_EVENT_STREAM) .returnResult(User.class) .getResponseBody() .take(3) .as(StepVerifier::create) .expectNextCount(3) .verifyComplete(); } }

九、性能优化建议

  1. 避免阻塞操作:不要在响应式链中调用阻塞方法

  2. 合理使用线程池:对阻塞操作使用publishOn切换到弹性线程池

  3. 背压处理:合理使用onBackpressureBufferonBackpressureDrop等策略

  4. 连接池配置:配置数据库、Redis等连接池大小

  5. 响应式驱动:使用响应式数据库驱动(如R2DBC、Reactive MongoDB)

十、实战项目结构

text

src/main/java/ ├── config/ # 配置类 ├── controller/ # 注解式控制器 ├── router/ # 函数式路由 ├── handler/ # 处理器函数 ├── service/ # 业务逻辑层 ├── repository/ # 响应式仓库 ├── model/ # 数据模型 └── exception/ # 异常处理

学习路径建议

  1. 先学习 Reactor:掌握 Mono/Flux 的常用操作符

  2. 理解背压机制:学习如何控制数据流

  3. 从注解式开始:如果你熟悉 Spring MVC,更容易上手

  4. 尝试函数式编程:理解 Router Functions 的优势

  5. 集成响应式数据库:实践完整的数据流处理

  6. 学习测试:掌握 WebTestClient 和 StepVerifier

  7. 官方文档:Spring WebFlux
  8. Project Reactor 文档:Reactor Reference Guide



版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/26 1:15:11

【建议收藏】35岁转行网络安全,行业缺口327万,附学习路线和资源

35岁转型搞安全是否还有戏&#xff1f; 放眼现在安全圈 00后的黑客CEO已经出场了 18岁的少年也开始穿梭于微软、谷歌、苹果各大国际公司的安全致谢榜 年轻的黑客们早已登上国际舞台&#xff0c;开始在世界顶级黑客大会上分享议题 40岁&#xff0c;对大多数人来说&#xff…

作者头像 李华
网站建设 2026/6/26 12:02:45

无人机视角土豆马铃薯洋芋苗病害检测数据集VOC+YOLO格式1539张2类别

注意图片不是十分清晰&#xff0c;具体看示例图片数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件)图片数量(jpg文件个数)&#xff1a;1539标注数量(xml文件个数)&#xff1a;153…

作者头像 李华
网站建设 2026/7/1 22:05:18

【效率真相】为什么越来越多的开发者选择点三电商API对接电商平台?

在电商生态日益复杂的今天&#xff0c;一个看似简单的需求——让企业的ERP或WMS系统能够接收和处理多平台的订单——正在成为无数开发团队耗时数月的“黑洞”。传统的对接路径要求开发者逐一入驻各电商开放平台&#xff0c;提交资质、等待审核、研读迥异的接口文档、处理千差万…

作者头像 李华
网站建设 2026/6/30 14:37:49

深度测评8个AI论文平台,MBA论文写作必备!

深度测评8个AI论文平台&#xff0c;MBA论文写作必备&#xff01; AI 工具如何重塑论文写作的未来 在当今这个信息爆炸的时代&#xff0c;MBA 学生和科研工作者正面临前所未有的挑战。无论是撰写高质量的论文&#xff0c;还是应对严格的查重要求&#xff0c;传统方法已经难以满…

作者头像 李华
网站建设 2026/7/1 7:01:31

护网行动备战与实战宝典:从个人备赛到团队攻坚的全攻略

护网行动备战与实战宝典&#xff1a;从个人备赛到团队攻坚的全攻略 近年来&#xff0c;护网行动已从“阶段性演练”升级为关键信息基础设施安全防护的“常态化考核”&#xff0c;对抗强度、攻击战术复杂度持续攀升——红队不仅模拟常规Web攻击&#xff0c;更频繁运用APT组织的…

作者头像 李华