Introduction
? Responsive programming is a programming paradigm for data flow and change propagation. It makes it easy to express static or dynamic Data flows in a programming language, and the related computational model automatically propagates the changed values through the data stream. We can build applications in a declarative way to create more sensitive and resilient applications, so Spring 5 adds a reaction system to its core framework and has begun to shift to declarative programming paradigm.
The benefits of responsive programming
Improves the readability of the code, so developers only need to focus on defining business logic.
In a high-concurrency environment, messages can be processed naturally.
You can control the flow between producers and consumers to avoid running out of memory.
For one or more threads, the IO binding task can be executed asynchronously and nonblocking without blocking the current thread.
- Can effectively manage the communication between multiple connected systems.
Application Scenarios
A large number of transaction processing services, such as the banking sector.
Notification Services for large online shopping apps, such as Amazon.
- Stock trading business in which stock prices change at the same time.
Spring 5.0 Preview
As the first responsive web framework in Java, Spring 5.0 has the biggest highlight of providing complete end-to-end responsive programming support.
As shown on the left side is the traditional servlet-based spring WEB MVC Framework, and on the right is Spring 5.0, the new Spring Webflux framework, based on the reactive streams, from the top down: Router Functions, Webflux,reactive streams three new components, including:
Router Functions: For standard spring MVC annotations such as superscript @controller, @RequestMapping, provides a functional style API for creating Router,handler and filter.
Webflux: A core component that coordinates the upstream and downstream components to provide responsive programming support.
- REACTIVE STREAMS: A support for back-pressure (backpressure) asynchronous data stream processing standards, mainstream implementation has Rxjava and reactor,spring Webflux The default integration is reactor.
Sample code
1. Create a project
Spring responsive development needs to be done in conjunction with spring boot, so use idea to create a springboot project, select the Spring initializr option, and the JDK selects more than 1.8.
Select next to set GroupID and Artifactid.
Select Next and select the Reactive Web option in the Web options to indicate that you want to create a responsive project, note that the Spring boot version is 2.0.2.
Select Next, set the project directory, click Finish to create the project.
2. Set up the service port
To avoid port collisions, we can configure the service port in the project's Application.properties file.
server.port=9002
3. Dependent Packages
Open the project's Pom.xml file, and you will find the following dependent packages
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </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>
which
The Spring-boot-starter-webflux:webflux dependency package is the core dependency package for responsive development, which contains the Spring-boot-starter-reactor-netty, Spring 5 Webflux package, By default, it is started by Netty.
Spring-boot-starter-test:springboot's Unit Testing tool library.
- Reactor-test:spring 5 provides an official library of testing tools for the RP Framework.
Summary
? Spring responsive development needs to be done in conjunction with spring boot, and requires the introduction of Spring-boot-starter-webflux and Reactor-test two dependency packages to support responsive development.
4. Create a web App with Webflux
Webflux is used in two ways, based on annotations and functional programming. This is done using functional programming, as follows:
4.1. Create an entity class
public class Good {? private int id; private String name; private String price;? public Good(int id,String name,String price){ this.id=id; this.name=name; this.price=price; }? 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 String getPrice() { return price; }? public void setPrice(String price) { this.price = price; }? @Override public String toString() { return "Good{" + "id=" + id + ", name=‘" + name + ‘\‘‘ + ", price=‘" + price + ‘\‘‘ + ‘}‘; }}
Analysis: Entity classes do not have any special operations, the original how to operate now or how to operate.
4.2. Create Goodgenerator
@Configurationpublic class GoodGenerator {? public Flux<Good> findGoods(){ List<Good> goods = new ArrayList<>(); goods.add(new Good(1,"小米","2000")); goods.add(new Good(2,"华为","4000")); goods.add(new Good(3,"苹果","8000")); return Flux.fromIterable(goods); }}
Analysis: The method here returns the flux type of data, flux is one of the most basic data types in RP, corresponding to the return operation of multi-valued data, the mono data type in RP, and one of the most basic data types, corresponding to the return operation of single value data.
Note: @configuration annotations are added to the Goodgenerator class here.
4.3. Create Goodhandler
@Component@Configurationpublic class GoodHandler {? private final Flux<Good> goods;? public GoodHandler(GoodGenerator goodGenerator) { this.goods = goodGenerator.findGoods(); }? public Mono<ServerResponse> hello(ServerRequest request) {? return ok().contentType(TEXT_PLAIN) .body(BodyInserters.fromObject("Hello Spring!")); }? public Mono<ServerResponse> echo(ServerRequest request) { return ok().contentType(APPLICATION_STREAM_JSON) .body(this.goods,Good.class); }}
Analysis: Handler is primarily used to process request operations, and will mono<serverresponse> return,mono<serverresponse> to encapsulate the response data, if the string can be used:
ok().contentType(TEXT_PLAIN).body(BodyInserters.fromObject("Hello Spring!"));
Operation, if the collection data can be used:
ok().contentType(APPLICATION_STREAM_JSON).body(this.goods,Good.class)
Operation.
4.4. Create Goodrouter
@Configurationpublic class GoodRouter { @Bean public RouterFunction<ServerResponse> route(GoodHandler goodHandler) {? return RouterFunctions .route(RequestPredicates.GET("/good") .and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),goodHandler::hello) .andRoute(RequestPredicates.GET("/goods") .and(RequestPredicates.accept(MediaType.APPLICATION_STREAM_JSON)),goodHandler::echo); }?}
Analysis: Goodrouter is primarily used to set request paths and convert HTTP requests, and you can use the route () method and the Androute method to set up multiple request paths and conversion actions.
Summary
? The HTTP request is forwarded by Goodrouter to the corresponding Handler,handler processing request and returns MONO<SERVERRESPONSE>, where router is similar to @requestmapping, Handler similar controller
4.4. Run the test
? entity classes, Goodgenerator, Goodhandler, Goodrouter have all been created, and we can run the project to open the browser for testing.
Browser input Http://localhost:9002/good, you can get to "Hello spring!" Text information
Browser input http://localhost:9002/goods, you can get to the collection information
So far, a simple Webflux example has been completed.
4.5. Unit Testing
In the project we can also use a new Spring 5 introduced Test tool class, webtestclient, specifically for testing RP applications, the code is as follows:
@RunWith(SpringRunner.class)@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)public class Spring5demoApplicationTests {? @Autowired private WebTestClient webTestClient;? @Test public void helloTest() { String s= webTestClient .get().uri("/good") .accept(MediaType.TEXT_PLAIN).exchange() .expectStatus().isOk().returnResult(String.class) .getResponseBody().blockFirst();? System.out.println(s); }? @Test public void findGoodsTest(){ webTestClient.get().uri("/goods") .accept(MediaType.APPLICATION_STREAM_JSON) .exchange().expectStatus().isOk() .expectHeader().contentType(MediaType.APPLICATION_STREAM_JSON) .returnResult(Good.class) .getResponseBody().collectList(); }}
When you create a webtestclient instance, you can see that writing unit tests for RP applications is also a streaming style of data that doesn't fall into the ground
Summarize
? In this case, Spring 5.0 's responsive programming is introduced here, it is simply a response to get started operation, but also can reflect the characteristics of responsive programming. Of course Spring 5.0 responsive programming is also not perfect, and it has limitations in troubleshooting, relying on library integration, data storage, and the support of the spring security rights framework.?
Getting Started with Spring5.0 responsive programming