012、Project Reactor

一、什么是Project Reactor

官网  https://projectreactor.io/

由表及里学 ProjectReactor   http://blog.yannxia.top/2018/06/26/java/spring/projectreactor/

即 响应式编程。主要解决了回调地狱(callback hell)的问题。

 

二、如何使用

1. 引入依赖

		<dependency>
			<groupId>io.projectreactor</groupId>
			<artifactId>reactor-core</artifactId>
		</dependency>

 

2. 例子

	@Override
	public void run(ApplicationArguments args) throws Exception {

		Flux.range(1, 6)
		        .doOnRequest(n -> log.info("Request {} number", n)) // 注意顺序造成的区别
		        .publishOn(Schedulers.elastic())
				.doOnComplete(() -> log.info("Publisher COMPLETE 1"))
				.map(i -> {
					log.info("Publish   thread: {}, i: {}", Thread.currentThread(), i);
//					return i / (3 - i);
					return i;
				})
//				.onErrorReturn(-1)  // onErrorReturn 和  onErrorResume 顺序,在前优先
				.onErrorResume(e -> {
					log.error("ErrorResume: {}", e.toString());
					return Mono.just(-2);
				})
				.doOnComplete(() -> log.info("Publisher COMPLETE 2"))
				.subscribeOn(Schedulers.elastic())
				.subscribe(i -> log.info("Subscribe thread: {}, i: {}", Thread.currentThread(), i)
						,e -> log.error("error: {}", e.toString())
						,() -> log.info("Subscriber COMPLETE")
//						,s -> s.request(4)
						);
		
		Thread.sleep(2000);
	}

 

二、redis with reactive

1. 引入依赖

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
		</dependency>

 

2. 例子

	private void reactiveRedis() throws InterruptedException {
		ReactiveHashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
		
		String KEY = "reactor-redis";
		
		CountDownLatch countDownLatch = new CountDownLatch(1);
		
		Flux.fromArray(new String[] {"123", "456"})
		    .publishOn(Schedulers.single())
		    .doOnComplete(() -> log.info("list ok"))
		    .flatMap(c -> {
                log.info("try to put {}: {}", c, c);
                return opsForHash.put(KEY, c, c);
            })
		    .doOnComplete(() -> log.info("set ok"))
		    .concatWith(redisTemplate.expire(KEY, Duration.ofMinutes(1)))
		    .doOnComplete(() -> log.info("expire ok"))
		    .onErrorResume(e -> {
                log.error("exception {}", e.getMessage());
                return Mono.just(false);
            })
		    .subscribe(b -> log.info("subscribe: {}", b)
		    		,
                    e -> log.error("Exception {}", e.getMessage())
                    ,
                    () -> countDownLatch.countDown()
                    );
		    ;
		    
		    countDownLatch.await();
	}

 

三、mongodb with reactive

1. 引入依赖

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
		</dependency>

 

2. 例子

	private void reactiveMongo() throws InterruptedException {
		CountDownLatch cdl = new CountDownLatch(2);
		
		List<Coffee> objectsToSave = Arrays.asList(new Coffee().setName("猫屎咖啡").setPrice(19).setCreateTime(new Date()).setUpdateTime(new Date()),
				new Coffee().setName("拿铁咖啡").setPrice(15).setCreateTime(new Date()).setUpdateTime(new Date()));
		
		mongoTemplate.insertAll(objectsToSave)
		    .publishOn(Schedulers.elastic())
		    .doOnNext(c -> log.info("Next: {}", c))
		    .doOnComplete(() -> {
		    	log.info("Runnable");
		    	mongoTemplate.updateMulti(Query.query(Criteria.where("price").gte(16)),
						        new Update().inc("price", -5)
								    .currentDate("updateTime"),
								Coffee.class)
				    .doFinally(s -> {
						cdl.countDown();
						log.info("Finnally 2, {}", s);
					})
					.subscribe(r -> log.info("Result is {}", r));
		    })
		    .doFinally(s -> {
				cdl.countDown();
				log.info("Finnally 1, {}", s);
			})
		    .count()
		    .subscribe(c -> log.info("Insert {} records", c));
		
		cdl.await();
	}

 

源码

Fork me on Gitee

转载于:https://my.oschina.net/tita/blog/3062656

<think>好的,用户现在想了解Project Reactor。首先,我需要回忆一下之前和用户讨论的内容。之前用户问过Spring WebFlux,而Project Reactor是WebFlux的核心依赖库。所以用户可能是在学习响应式编程,特别是Spring的相关技术,想深入理解底层原理。 用户可能是开发者,正在构建高并发的应用,或者在学习如何优化应用性能。他们可能已经知道Spring MVC,现在想转向响应式编程,但遇到了Project Reactor这个新概念,需要进一步了解。 接下来,我需要确定用户的真实需求。他们可能不仅仅想要一个简单的定义,而是想了解Reactor的核心概念、如何使用、优缺点以及实际应用场景。此外,用户可能还想知道Reactor与其他库(比如RxJava)的区别,或者如何在项目中应用它。 我需要组织信息,结构要清晰。先介绍Reactor是什么,然后核心概念比如Flux和Mono,背压机制,调度器。接着对比RxJava,适用场景,优缺点,最后给出示例代码。这样用户能逐步深入理解。 要注意之前用户提到过WebFlux,所以需要强调Reactor在其中的作用,比如作为响应式流的具体实现。同时,要避免技术术语过多,用易懂的例子解释,比如用Flux.just()创建数据流。 还要提醒用户可能遇到的挑战,比如调试困难和学习曲线陡峭,这样他们能权衡是否适合项目使用。最后,提供示例代码帮助用户快速上手,并给出使用建议,比如在IO密集型场景使用。 需要检查是否有遗漏点,比如背压处理的具体机制,或者如何与Spring集成。确保回答准确,并且符合用户的学习路径,从概念到实践,逐步展开。</think>以下是关于 **Project Reactor** 的详细介绍: --- ### 一、核心定义 **Project Reactor** 是一个基于 **Reactive Streams 规范** 的响应式编程库,专为 Java 8+ 设计。它是 Spring WebFlux 的默认响应式引擎,用于构建非阻塞、高并发的异步应用。 --- ### 二、核心概念 1. **响应式流模型** - 提供两种核心容器: - **`Flux<T>`**:表示包含 `0~N` 个元素的异步数据流(例如:数据库查询结果流)。 - **`Mono<T>`**:表示包含 `0~1` 个元素的异步结果(例如:单个 HTTP 请求响应)。 ```java Flux<Integer> numbers = Flux.just(1, 2, 3); // 创建包含三个元素的流 Mono<String> name = Mono.just("Alice"); // 创建单个元素的流 ``` 2. **背压(Backpressure)** - 消费者通过主动请求(Pull)控制数据流速,避免生产者过载。 - 示例:当消费者处理速度较慢时,通过 `request(n)` 限制数据拉取量。 3. **操作符(Operators)** - 提供丰富的链式操作方法(类似 Java Stream API),如 `map`, `filter`, `flatMap` 等。 ```java Flux.range(1, 5) .map(i -> i * 2) // 转换每个元素 .filter(i -> i > 5) // 过滤元素 .subscribe(System.out::println); // 输出 6, 8, 10 ``` 4. **调度器(Schedulers)** - 控制线程执行模型(如并行、弹性线程池): - `Schedulers.immediate()`:当前线程执行。 - `Schedulers.parallel()`:固定大小线程池(适合 CPU 密集型任务)。 - `Schedulers.elastic()`:无界线程池(适合 I/O 密集型任务)。 --- ### 三、与 RxJava 对比 | 特性 | Project Reactor | RxJava | |-----------------------|------------------------------|----------------------------| | **目标平台** | Java 8+ | 多语言(Java、Kotlin等) | | **集成 Spring** | 官方支持(Spring WebFlux) | 需手动适配 | | **背压实现** | 原生支持 Reactive Streams | 通过扩展库支持 | | **调试工具** | 提供 `Hooks.onOperatorDebug` | 依赖第三方工具 | --- ### 四、适用场景 1. **高吞吐服务** 如实时推送系统(股票行情、聊天消息)。 2. **微服务通信** 非阻塞 HTTP 客户端(如 WebClient)调用其他服务。 3. **流式数据处理** 处理 Kafka 消息流或数据库变更流(Change Data Capture)。 --- ### 五、核心优势 1. **资源高效** - 少量线程处理高并发请求(如 Netty 的 EventLoop 模型)。 2. **无缝集成 Spring** - 与 Spring WebFlux、Spring Data Reactive 深度整合。 3. **丰富的错误处理** - 提供 `onErrorReturn`, `onErrorResume` 等操作符优雅处理异常。 ```java Flux.just(1, 2, 0) .map(i -> 10 / i) .onErrorResume(e -> Flux.just(-1)) // 发生异常时返回-1 .subscribe(System.out::println); // 输出 10, 5, -1 ``` --- ### 六、局限性 1. **调试困难** 异步调用链的堆栈信息不直观。 2. **学习曲线陡峭** 需理解响应式编程思维(如数据流、延迟执行)。 3. **阻塞操作破坏模型** 若误用阻塞代码(如 `Thread.sleep()`),会导致性能下降。 --- ### 七、代码示例 ```java // 1. 创建响应式 REST 端点 @RestController public class UserController { @GetMapping("/users") public Flux<User> getUsers() { return userRepository.findAll(); // 非阻塞查询 } } // 2. 组合多个流 Mono<User> user = userRepository.findById("1"); Mono<Order> order = orderRepository.findByUserId("1"); Mono<UserOrder> result = user.zipWith(order, (u, o) -> new UserOrder(u, o)); // 3. 使用调度器切换线程 Flux.range(1, 10) .parallel() .runOn(Schedulers.parallel()) // 切换到并行线程池 .map(i -> i * i) .subscribe(); ``` --- ### 八、使用建议 1. **优先场景** - 需要处理 `10,000+` 并发连接的 I/O 密集型服务。 - 已使用响应式数据库(如 MongoDB Reactive、R2DBC)。 2. **避免场景** - 依赖传统阻塞式库(如 JDBC、同步文件读写)。 - 团队缺乏响应式编程经验。 --- 通过 Project Reactor,开发者可以高效利用系统资源,但需权衡其复杂性与实际需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值