java react_Java 9React流

java react

Java 9 Reactive Streams allows us to implement non-blocking asynchronous stream processing. This is a major step towards applying reactive programming model to core java programming.

Java 9 Reactive Streams允许我们实现非阻塞异步流处理。 这是将React式编程模型应用于核心Java编程的重要一步。

If you are new to reactive programming, please read Reactive Manifesto and go through short notes on Reactive Streams. RxJava and Akka Streams have been the popular implementation of reactive streams. Now java 9 has introduced reactive streams support through java.util.concurrent.Flow API.

如果您不熟悉React式编程,请阅读“ React式宣言”,并阅读有关“ React式流”的简短说明。 RxJava和Akka流已成为React流的流行实现。 现在,java 9通过java.util.concurrent.Flow API引入了React流支持。

Java 9React流 (Java 9 Reactive Streams)

Reactive Streams is about asynchronous processing of stream, so there should be a Publisher and a Subscriber. The Publisher publishes the stream of data and the Subscriber consumes the data.

React性流是关于流的异步处理的,因此应该有一个Publisher和一个Subscriber 。 发布者发布数据流,而订阅者使用数据。

Sometimes we have to transform the data between Publisher and Subscriber. Processor is the entity sitting between the end publisher and subscriber to transform the data received from publisher so that subscriber can understand it. We can have a chain of processors.

有时我们必须在发布者和订阅者之间转换数据。 处理器是位于最终发布者和订阅者之间的实体,用于转换从发布者接收的数据,以便订阅者可以理解它。 我们可以拥有一连串的处理器。

It’s very clear from the above image that Processor works both as Subscriber and a Publisher.

从上图中可以很清楚地看到,Processor既可以作为订阅服务器,也可以作为发布服务器。

Java 9 Flow API (Java 9 Flow API)

Java 9 Flow API implements the Reactive Streams Specification. Flow API is a combination of Iterator and Observer pattern. Iterator works on pull model where application pulls items from the source, whereas Observer works on push model and reacts when item is pushed from source to application.

Java 9 Flow API实现了Reactive Streams规范 。 Flow API是IteratorObserver模式的组合。 Iterator在拉模型上工作,其中应用程序从源中拉出项目,而Observer在推模型上工作,并在将项目从源推到应用程序时做出React。

Java 9 Flow API subscriber can request for N items while subscribing to the publisher. Then the items are pushed from publisher to subscriber until there are no more items left to push or some error occurs.

Java 9 Flow API

Java 9 Flow API订阅者可以在订阅发布者的同时请求N个项目。 然后将项目从发布者推送到订阅者,直到没有其他项目要推送或出现某些错误为止。

Java 9 Flow API类和接口 (Java 9 Flow API Classes and Interfaces)

Let’s have a quick look at Flow API classes and interfaces.

让我们快速看一下Flow API类和接口。

  • java.util.concurrent.Flow: This is the main class of Flow API. This class encapsulates all the important interfaces of the Flow API. This is a final class and we can’t extend it.

    java.util.concurrent.Flow :这是Flow API的主要类。 此类封装了Flow API的所有重要接口。 这是最后一堂课,我们不能扩展它。
  • java.util.concurrent.Flow.Publisher: This is a functional interface and every publisher has to implement it’s subscribe method to add the given subscriber to receive messages.

    java.util.concurrent.Flow.Publisher :这是一个功能接口,每个发布者都必须实现它的subscription方法,以添加给定的订阅者来接收消息。
  • java.util.concurrent.Flow.Subscriber: Every subscriber has to implement this interface. The methods in the subscriber are invoked in strict sequential order. There are four methods in this interface:
    1. onSubscribe: This is the first method to get invoked when subscriber is subscribed to receive messages by publisher. Usually we invoke subscription.request to start receiving items from processor.
    2. onNext: This method gets invoked when an item is received from publisher, this is where we implement our business logic to process the stream and then request for more data from publisher.
    3. onError: This method is invoked when an irrecoverable error occurs, we can do cleanup taks in this method, such as closing database connection.
    4. onComplete: This is like finally method and gets invoked when no other items are being produced by publisher and publisher is closed. We can use it to send notification of successful processing of stream.

    java.util.concurrent.Flow.Subscriber :每个订阅者都必须实现此接口。 订户中的方法以严格的顺序调用。 此界面中有四种方法:
    1. onSubscribe :这是订阅服务器订阅发布者以接收消息时调用的第一种方法。 通常,我们调用subscription.request开始从处理器接收项目。
    2. onNext :当从发布者处收到项目时,将调用此方法,这是我们在其中实现业务逻辑以处理流然后向发布者请求更多数据的地方。
    3. onError :发生不可恢复的错误时,将调用此方法,我们可以使用此方法清理任务,例如关闭数据库连接。
    4. onComplete :这类似于finally方法,并且在发布者没有生产任何其他项目并且关闭发布者时被调用。 我们可以使用它发送成功处理流的通知。
  • java.util.concurrent.Flow.Subscription: This is used to create asynchronous non-blocking link between publisher and subscriber. Subscriber invokes its request method to demand items from publisher. It also has cancel method to cancel the subscription i.e. closing the link between publisher and subscriber.

    java.util.concurrent.Flow.Subscription :这用于在发布者和订阅者之间创建异步非阻塞链接。 订阅者调用其request方法以向发布者request项目。 它还具有cancel方法来取消订阅,即关闭发布者和订阅者之间的链接。
  • java.util.concurrent.Flow.Processor: This interface extends both Publisher and Subscriber, this is used to transform the message between publisher and subscriber.

    java.util.concurrent.Flow.Processor :此接口扩展了发布者和订阅者,用于在发布者和订阅者之间转换消息。
  • java.util.concurrent.SubmissionPublisher: A Publisher implementation that asynchronously issues submitted items to current subscribers until it is closed. It uses Executor framework We will use this class in reactive stream examples to add subscriber and then submit items to them.

    java.util.concurrent.SubmissionPublisher :一个Publisher实现,它异步地将提交的项目发布给当前的订阅者,直到关闭为止。 它使用Executor框架。我们将在React流示例中使用此类来添加订户,然后向其提交项目。

Java 9React流示例 (Java 9 Reactive Stream Example)

Let’s start with a simple example where we will implement Flow API Subscriber interface and use SubmissionPublisher to create publisher and send messages.

让我们从一个简单的示例开始,在该示例中,我们将实现Flow API Subscriber接口并使用SubmissionPublisher创建发布者并发送消息。

流数据 (Stream Data)

Let’s say we have an Employee class that will be used to create the stream message to be sent from publisher to subscriber.

假设我们有一个Employee类,它将用于创建要从发布者发送到订阅者的流消息。

package com.journaldev.reactive.beans;

public class Employee {

	private int id;
	private String name;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	public Employee(int i, String s) {
		this.id = i;
		this.name = s;
	}
	
	public Employee() {
	}
	
	@Override
	public String toString() {
		return "[id="+id+",name="+name+"]";
	}
}

We also have a utility class to create a list of employees for our example.

我们还有一个实用程序类,可以为我们的示例创建一个雇员列表。

package com.journaldev.reactive_streams;

import java.util.ArrayList;
import java.util.List;

import com.journaldev.reactive.beans.Employee;

public class EmpHelper {

	public static List<Employee> getEmps() {

		Employee e1 = new Employee(1, "Pankaj");
		Employee e2 = new Employee(2, "David");
		Employee e3 = new Employee(3, "Lisa");
		Employee e4 = new Employee(4, "Ram");
		Employee e5 = new Employee(5, "Anupam");
		
		List<Employee> emps = new ArrayList<>();
		emps.add(e1);
		emps.add(e2);
		emps.add(e3);
		emps.add(e4);
		emps.add(e5);
		
		return emps;
	}

}

订户 (Subscriber)

package com.journaldev.reactive_streams;

import java.util.concurrent.Flow.Subscriber;
import java.util.concurrent.Flow.Subscription;

import com.journaldev.reactive.beans.Employee;

public class MySubscriber implements Subscriber<Employee> {

	private Subscription subscription;
	
	private int counter = 0;
	
	@Override
	public void onSubscribe(Subscription subscription) {
		System.out.println("Subscribed");
		this.subscription = subscription;
		this.subscription.request(1); //requesting data from publisher
		System.out.println("onSubscribe requested 1 item");
	}

	@Override
	public void onNext(Employee item) {
		System.out.println("Processing Employee "+item);
		counter++;
		this.subscription.request(1);
	}

	@Override
	public void onError(Throwable e) {
		System.out.println("Some error happened");
		e.printStackTrace();
	}

	@Override
	public void onComplete() {
		System.out.println("All Processing Done");
	}

	public int getCounter() {
		return counter;
	}

}
  • Subscription variable to keep reference so that request can be made in onNext method.

    保留引用的Subscription变量,以便可以在onNext方法中进行请求。
  • counter variable to keep count of number of items processed, notice that it’s value is increased in onNext method. This will be used in our main method to wait for execution to finish before ending the main thread.

    counter变量,用于保持已处理项目数的计数,请注意,它的值在onNext方法中增加了。 这将在我们的main方法中用于等待执行完成,然后再结束主线程。
  • Subscription request is invoked in onSubscribe method to start the processing. Also notice that it’s again called in onNext method after processing the item, demanding next item to process from the publisher.

    订阅请求在onSubscribe方法中被调用以开始处理。 还要注意,在处理完该项目后,它再次在onNext方法中调用,要求发布者处理下一个项目。
  • onError and onComplete doesn’t have much here, but in real world scenario they should be used to perform corrective measures when error occurs or cleanup of resources when processing completes successfully.

    onErroronComplete在这里没有太多内容,但是在实际情况下,应该在发生错误时使用它们来执行纠正措施,或者在处理成功完成时清理资源。

React式流测试程序 (Reactive Stream Test Program)

We will use SubmissionPublisher as Publisher for our examples, so let’s look at the test program for our reactive stream implementation.

我们将使用SubmissionPublisher作为发布者作为示例,因此让我们看一下响应流实现的测试程序。

package com.journaldev.reactive_streams;

import java.util.List;
import java.util.concurrent.SubmissionPublisher;

import com.journaldev.reactive.beans.Employee;

public class MyReactiveApp {

	public static void main(String args[]) throws InterruptedException {

		// Create Publisher
		SubmissionPublisher<Employee> publisher = new SubmissionPublisher<>();

		// Register Subscriber
		MySubscriber subs = new MySubscriber();
		publisher.subscribe(subs);

		List<Employee> emps = EmpHelper.getEmps();

		// Publish items
		System.out.println("Publishing Items to Subscriber");
		emps.stream().forEach(i -> publisher.submit(i));

		// logic to wait till processing of all messages are over
		while (emps.size() != subs.getCounter()) {
			Thread.sleep(10);
		}
		// close the Publisher
		publisher.close();

		System.out.println("Exiting the app");

	}

}

The most important piece of above code is subscribe and submit methods invocation of publisher. We should always close publisher to avoid any memory leaks.

上面的代码最重要的部分是发布subscribesubmit方法调用。 我们应该始终关闭发布者,以避免任何内存泄漏。

We will get following output when above program is executed.

当执行上述程序时,我们将得到以下输出。

Subscribed
Publishing Items to Subscriber
onSubscribe requested 1 item
Processing Employee [id=1,name=Pankaj]
Processing Employee [id=2,name=David]
Processing Employee [id=3,name=Lisa]
Processing Employee [id=4,name=Ram]
Processing Employee [id=5,name=Anupam]
Exiting the app
All Processing Done

Note that if we won’t have logic for main method to wait before all the items are processed, then we will get unwanted results.

请注意,如果我们没有让main方法等待所有项目都经过处理的逻辑,那么我们将得到不想要的结果。

消息转换示例 (Message Transformation Example)

Processor is used to transform the message between a publisher and subscriber. Let’s say we have another subscriber which is expecting a different type of message to process. Let’s say this new message type is Freelancer.

处理器用于在发布者和订阅者之间转换消息。 假设我们有另一个订户,它希望处理不同类型的消息。 假设此新消息类型为Freelancer

package com.journaldev.reactive.beans;

public class Freelancer extends Employee {

	private int fid;

	public int getFid() {
		return fid;
	}

	public void setFid(int fid) {
		this.fid = fid;
	}
	
	public Freelancer(int id, int fid, String name) {
		super(id, name);
		this.fid = fid;
	}
	
	@Override
	public String toString() {
		return "[id="+super.getId()+",name="+super.getName()+",fid="+fid+"]";
	}
}

We have a new subscriber to consume Freelancer stream data.

我们有一个新订阅者可以使用Freelancer流数据。

package com.journaldev.reactive_streams;

import java.util.concurrent.Flow.Subscriber;
import java.util.concurrent.Flow.Subscription;

import com.journaldev.reactive.beans.Freelancer;

public class MyFreelancerSubscriber implements Subscriber<Freelancer> {

	private Subscription subscription;
	
	private int counter = 0;
	
	@Override
	public void onSubscribe(Subscription subscription) {
		System.out.println("Subscribed for Freelancer");
		this.subscription = subscription;
		this.subscription.request(1); //requesting data from publisher
		System.out.println("onSubscribe requested 1 item for Freelancer");
	}

	@Override
	public void onNext(Freelancer item) {
		System.out.println("Processing Freelancer "+item);
		counter++;
		this.subscription.request(1);
	}

	@Override
	public void onError(Throwable e) {
		System.out.println("Some error happened in MyFreelancerSubscriber");
		e.printStackTrace();
	}

	@Override
	public void onComplete() {
		System.out.println("All Processing Done for MyFreelancerSubscriber");
	}

	public int getCounter() {
		return counter;
	}

}

处理器 (Processor)

The important part is the implementation of Processor interface. Since we want to utilize the SubmissionPublisher, we would extend it and use it wherever applicable.

重要的部分是Processor接口的实现。 由于我们想利用SubmissionPublisher ,我们将对其进行扩展并在适用的地方使用它。

package com.journaldev.reactive_streams;

import java.util.concurrent.Flow.Processor;
import java.util.concurrent.Flow.Subscription;
import java.util.concurrent.SubmissionPublisher;
import java.util.function.Function;

import com.journaldev.reactive.beans.Employee;
import com.journaldev.reactive.beans.Freelancer;

public class MyProcessor extends SubmissionPublisher<Freelancer> implements Processor<Employee, Freelancer> {

	private Subscription subscription;
	private Function<Employee,Freelancer> function;
	
	public MyProcessor(Function<Employee,Freelancer> function) {  
	    super();  
	    this.function = function;  
	  }  
	
	@Override
	public void onSubscribe(Subscription subscription) {
		this.subscription = subscription;
		subscription.request(1);
	}

	@Override
	public void onNext(Employee emp) {
		submit((Freelancer) function.apply(emp));  
	    subscription.request(1);  
	}

	@Override
	public void onError(Throwable e) {
		e.printStackTrace();
	}

	@Override
	public void onComplete() {
		System.out.println("Done");
	}

}
  • Function will be used to convert Employee object to Freelancer object.

    Function将用于将Employee对象转换为Freelancer对象。
  • We will convert incoming Employee message to Freelancer message in onNext method and then use SubmissionPublisher submit method to send it to the subscriber.

    我们将在onNext方法中将传入的Employee消息转换为Freelancer消息,然后使用SubmissionPublisher onNext方法将其发送给订阅者。
  • Since Processor works as both subscriber and publisher, we can create a chain of processors between end publishers and subscribers.

    由于Processor同时充当订户和发布者,因此我们可以在最终发布者和订户之间创建处理器链。

邮件转换测试 (Message Transformation Test)

package com.journaldev.reactive_streams;

import java.util.List;
import java.util.concurrent.SubmissionPublisher;

import com.journaldev.reactive.beans.Employee;
import com.journaldev.reactive.beans.Freelancer;

public class MyReactiveAppWithProcessor {

	public static void main(String[] args) throws InterruptedException {
		// Create End Publisher
		SubmissionPublisher<Employee> publisher = new SubmissionPublisher<>();

		// Create Processor
		MyProcessor transformProcessor = new MyProcessor(s -> {
			return new Freelancer(s.getId(), s.getId() + 100, s.getName());
		});

		//Create End Subscriber
		MyFreelancerSubscriber subs = new MyFreelancerSubscriber();

		//Create chain of publisher, processor and subscriber
		publisher.subscribe(transformProcessor); // publisher to processor
		transformProcessor.subscribe(subs); // processor to subscriber

		List<Employee> emps = EmpHelper.getEmps();

		// Publish items
		System.out.println("Publishing Items to Subscriber");
		emps.stream().forEach(i -> publisher.submit(i));

		// Logic to wait for messages processing to finish
		while (emps.size() != subs.getCounter()) {
			Thread.sleep(10);
		}

		// Closing publishers
		publisher.close();
		transformProcessor.close();

		System.out.println("Exiting the app");
	}

}

Read the comments in the program to properly understand it, most important change is the creation of producer-processor-subscriber chain. We will get following output when above program is executed.

阅读程序中的注释以正确理解它,最重要的变化是创建了生产者-处理器-用户链。 当执行上述程序时,我们将得到以下输出。

Subscribed for Freelancer
Publishing Items to Subscriber
onSubscribe requested 1 item for Freelancer
Processing Freelancer [id=1,name=Pankaj,fid=101]
Processing Freelancer [id=2,name=David,fid=102]
Processing Freelancer [id=3,name=Lisa,fid=103]
Processing Freelancer [id=4,name=Ram,fid=104]
Processing Freelancer [id=5,name=Anupam,fid=105]
Exiting the app
All Processing Done for MyFreelancerSubscriber
Done

取消订阅 (Cancel Subscription)

We can use Subscription cancel method to stop receiving message in subscriber. Note that if we cancel the subscription, then subscriber will not receive onComplete or onError signal.

我们可以使用订阅取消方法停止在订阅者中接收消息。 请注意,如果我们取消订阅,则订阅者将不会收到onComplete或onError信号。

Here is a sample code where subscriber is consuming only 3 messages and then canceling the subscription.

这是一个示例代码,其中订阅者仅使用3条消息,然后取消订阅。

@Override
public void onNext(Employee item) {
	System.out.println("Processing Employee "+item);
	counter++;
	if(counter==3) {
		this.subscription.cancel();
		return;
	}
	this.subscription.request(1);
}

Note that in this case, our logic to halt main thread before all the messages are processed will go into infinite loop. We can add some additional logic for this scenario, may be some global variable to look for if subscriber has stopped processing or canceled subscription.

请注意,在这种情况下,在处理所有消息之前暂停主线程的逻辑将进入无限循环。 我们可以为此场景添加一些其他逻辑,可能是一些全局变量,以查找订户是否已停止处理或取消了订户。

背压 (Back Pressure)

When publisher is producing messages in much faster rate than it’s being consumed by subscriber, back pressure gets built. Flow API doesn’t provide any mechanism to signal about back pressure or to deal with it. But we can devise our own strategy to deal with it, such as fine tuning the subscriber or reducing the message producing rate. You can read how RxJava deals with Back Pressure.

当发布者以比订阅者消耗的速度快得多的速度生成消息时,就会形成背压。 Flow API没有提供任何机制来发出有关背压的信号或进行处理。 但是我们可以设计自己的策略来处理它,例如微调用户或降低消息产生率。 您可以阅读RxJava如何处理Back Pressure

摘要 (Summary)

Java 9 Flow API is a good move towards reactive programming and to create asynchronous non-blocking application. However creating a true reactive application is possible only when all the systems API support it.

Java 9 Flow API是朝着React性编程和创建异步非阻塞应用程序迈出的良好一步。 但是,只有在所有系统API都支持的情况下,才可以创建真正的React式应用程序。

GitHub Project. GitHub Project下载本教程中使用的示例代码。

翻译自: https://www.journaldev.com/20723/java-9-reactive-streams

java react

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值