此内容没有您所选择的语言版本。
Chapter 5. Developing reactive applications using Spring Boot with Eclipse Vert.x
Eclipse Vert.x reactive components for Spring Boot are provided as a Technology Preview.
This section provides an introduction to developing applications in a reactive way using Spring Boot starters based on Spring Boot and Eclipse Vert.x. The following examples demonstrate how you can use the starters to create reactive applications.
5.1. Introduction to Spring Boot with Eclipse Vert.x 复制链接链接已复制到粘贴板!
The Spring reactive stack is build on Project Reactor, a reactive library that implements backpressure and is compliant with the Reactive Streams specification. It provides the Flux and Mono functional API types that enable asynchronous event stream processing.
On top of Project Reactor, Spring provides WebFlux, an asynchronous event-driven web application framework. While WebFlux is designed to work primarily with Reactor Netty, it can also operate with other reactive HTTP servers, such as Eclipse Vert.x.
Spring WebFlux and Reactor enable you to create applications that are:
- Non-blocking: The application continues to handle further requests when waiting for a response from a remote component or service that is required to complete the current request.
- Asynchronous: the application responds to events from an event stream by generating response events and publishing them back to the event stream where they can be picked up by other clients in the application.
- Event-driven: The application responds to events generated by the user or by another service, such as mouse clicks, HTTP requests, or new files being added to a storage.
- Scalable: Increasing the number of Publishers or Subscribers to match the required event processing capacity of an application only results in a slight increase in the complexity of routing requests between individual clients in the application. Reactive applications can handle large numbers of events using fewer computing and networking resources as compared to other application programming models.
- Resilient: The application can handle failure of services it depend on without a negative impact on its overall quality of service.
Additional advantages of using Spring WebFlux include:
- Similarity with SpringMVC
- The SpringMVC API types and WebFlux API types are similar, and it is easy for developers to apply knowledge of SpringMVC to programming applications with WebFlux.
The Spring Reactive offering by Red Hat brings the benefits of Reactor and WebFlux to OpenShift and stand-alone RHEL, and introduces a set of Eclipse Vert.x extensions for the WebFLux framework. This allows you to retain the level of abstraction and rapid prototyping capabilities of Spring Boot, and provides an asynchronous IO API that handles the network communications between the services in your application in a fully reactive manner.
- Annotated controllers support
- WebFlux retains the endpoint controller annotations introduced by SpringMVC (Both SpringMVC and WebFlux support reactive RxJava2 and Reactor return types).
- Functional programming support
-
Reactor interacts with the Java 8 Functional API, as well as
CompletablebFuture, andStreamAPIs. In addition to annotation-based endpoints, WebFlux also supports functional endpoints.
Additional resources
See the following resources for additional in-depth information on the implementation details of technologies that are part of the Spring Reactive stack:
- The Reactive Manifesto
- Reactive Streams specification
- Spring Framework reference documentation: Web Applications on Reactive Stack
- Reactor Netty documentation
-
API Reference page for the
Monoclass in Project Reactor Documentation -
API Reference page for the
Fluxclass in Project Reactor Documentation
5.2. Reactive Spring Web 复制链接链接已复制到粘贴板!
The spring-web module provides the foundational elements of the reactive capabilities of Spring WebFlux, including:
-
HTTP abstractions provided by the
HttpHandlerAPI - Reactive Streams adapters for supported servers (Eclipse Vert.x, Undertow and others)
Codecs for encoding and decoding event stream data. This includes:
-
DataBuffer, an abstraction for different types of byte buffer representations (NettyByteBuf,java.nio.ByteBuffer, as well as others) - Low-level contracts to encode and decode content independent of HTTP
-
HttpMessageReaderandHTTPMessageWritercontracts to encode and decode HTTP message content
-
-
The
WebHandlerAPI (a counterpart to the Servlet 3.1 I/O API that uses non-blocking contracts).
When designing your web application, you can choose between 2 programming models that Spring WebFlux provides:
- Annotated Controllers
-
Annotated controllers in Spring WebFlux are consistent with Spring MVC, and are based on the same annotations from the
spring-webmodule. In addition to thespring-webmodule from SpringMVC, its WebFlux counterpart also supports reactive@RequestBodyarguments. - Functional Endpoints
- Functional endpoints provided by spring WebFlux on Java 8 Lambda expressions and functional APIs, this programming model relies on a dedicated library (Reactor, in this case) that routes and handles requests. As opposed to annotation-based endpoint controllers that rely on declaring Intent and using callbacks to complete an activity, the reactive model based on functional endpoints allows request handling to be fully controlled by the application.
Create a basic reactive Hello World HTTP web service using Spring Boot and WebFlux.
Prerequisites
- JDK 8 or JDK 11 installed
- Maven installed
- A Maven-based application project configured to use Spring Boot
Procedure
Add
vertx-spring-boot-starter-httpas a dependency in thepom.xmlfile of your project.pom.xml<project> ... <dependencies> ... <dependency> <groupId>dev.snowdrop</groupId> <artifactId>vertx-spring-boot-starter-http</artifactId> </dependency> ... <dependencies> ... </project>Create a main class for your application and define the router and handler methods.
HttpSampleApplication.javapackage dev.snowdrop.vertx.sample.http; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; import static org.springframework.web.reactive.function.BodyInserters.fromObject; import static org.springframework.web.reactive.function.server.RouterFunctions.route; import static org.springframework.web.reactive.function.server.ServerResponse.ok; @SpringBootApplication public class HttpSampleApplication { public static void main(String[] args) { SpringApplication.run(HttpSampleApplication.class, args); } @Bean public RouterFunction<ServerResponse> helloRouter() { return route() .GET("/hello", this::helloHandler) .build(); } private Mono<ServerResponse> helloHandler(ServerRequest request) { String name = request .queryParam("name") .orElse("World"); String message = String.format("Hello, %s!", name); return ok() .body(fromObject(message)); } }OPTIONAL: Run and test your application locally:
Navigate to the root directory of your Maven project:
$ cd myAppPackage your application:
$ mvn clean packageStart your application from the command line:
$ java -jar target/vertx-spring-boot-sample-http.jarIn a new terminal window, issue an HTTP request on the
/helloendpoint:$ curl localhost:8080/hello Hello, World!Provide a custom name with your request to get a personalized response:
$ curl http://localhost:8080/hello?name=John Hello, John!
Additional resources
- You can deploy your application to an OpenShift cluster using Fabric8 Maven Plugin.
- You can also configure your application for deployment on stand-alone Red Hat Enterprise Linux.
- For more detail on creating reactive web services with Spring Boot, see the reactive REST service development guide in the Spring community documentation.
Create a reactive Hello World HTTP web service with basic form-based authentication using Spring Security and WebFlux starters.
Prerequisites
- JDK 8 or JDK 11 installed
- Maven installed
- A Maven-based application project configured to use Spring Boot
Procedure
Add
vertx-spring-boot-starter-httpandspring-boot-starter-securityas dependencies in thepom.xmlfile of your project.pom.xml<project> ... <dependencies> ... <dependency> <groupId>dev.snowdrop</groupId> <artifactId>vertx-spring-boot-starter-http</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> ... <dependencies> ... </project>Create an endpoint controller class for your application:
HelloController.javapackage dev.snowdrop.vertx.sample.http.security; import java.security.Principal; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; @RestController public class HelloController { @GetMapping("/") public Mono<String> hello(Mono<Principal> principal) { return principal .map(Principal::getName) .map(this::helloMessage); } private String helloMessage(String username) { return "Hello, " + username + "!"; } }Create the main class of your application:
HttpSecuritySampleApplication.javapackage dev.snowdrop.vertx.sample.http.security; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class HttpSecuritySampleApplication { public static void main(String[] args) { SpringApplication.run(HttpSecuritySampleApplication.class, args); } }Create a
SecurityConfigurationclass that stores the user credentials for accessing the/helloendpoint.SecurityConfiguration.javapackage dev.snowdrop.vertx.sample.http.security; import org.springframework.context.annotation.Bean; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; @EnableWebFluxSecurity public class SecurityConfiguration { @Bean public MapReactiveUserDetailsService userDetailsService() { UserDetails user = User.withDefaultPasswordEncoder() .username("user") .password("user") .roles("USER") .build(); return new MapReactiveUserDetailsService(user); } }OPTIONAL: Run and test your application locally:
Navigate to the root directory of your Maven project:
$ cd myAppPackage your application:
$ mvn clean packageStart your application from the command line:
$ java -jar target/vertx-spring-boot-sample-http-security.jar-
Navigate to
http://localhost:8080using a browser to access the login screen. Log in using the credentials below:
- username: user
- password: user
You receive a customized greeting when you are logged in:
Hello, user!-
Navigate to
http://localhost:8080/logoutusing a web browser and use the Log out button to log out of your application. Alternatively, use a terminal to make an unauthenticated HTTP request on
localhost:8080. You receive HTTP401 Unauthorizedresponse from your application.$ curl -I http://localhost:8080 HTTP/1.1 401 Unauthorized WWW-Authenticate: Basic realm="Realm" Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: 0 X-Content-Type-Options: nosniff X-Frame-Options: DENY X-XSS-Protection: 1 ; mode=block Referrer-Policy: no-referrerIssue an authenticated request using the example user credentials. You receive a personalized response.
$ curl -u user:user http://localhost:8080 Hello, user!
Additional resources
- You can deploy your application to an OpenShift cluster using Fabric8 Maven Plugin.
- You can also configure your application for deployment on stand-alone Red Hat Enterprise Linux.
- For the full specification of the Basic HTTP authentication scheme, see document RFC-7617.
- For the full specification of HTTP authentication extensions for interactive clients, including form-based authentication, see document RFC-8053.
Set up OAuth2 authentication for your reactive Spring Boot application and authenticate using your client ID and client secret.
Prerequisites
- JDK 8 or JDK 11 installed
- A GitHub account
- Maven installed
- A Maven-based application project configured to use Spring Boot
Procedure
Register a new OAuth 2 application on your Github account. Ensure that you provide the following values in the registration form:
-
Homepage URL:
http://localhost:8080 Authorization callback URL:
http://localhost:8080/login/oauth2/code/githubEnsure that you save the client ID and a client secret that you receive upon completing the registration.
-
Homepage URL:
Add the following dependencies in the
pom.xmlfile of your project:-
vertx-spring-boot-starter-http -
spring-boot-starter-security -
spring-boot-starter-oauth2-client reactor-nettyNote that the
reactor-nettyclient is required to ensure thatspring-boot-starter-oauth2-clientworks properly.pom.xml<project> ... <dependencies> ... <dependency> <groupId>dev.snowdrop</groupId> <artifactId>vertx-spring-boot-starter-http</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-client</artifactId> </dependency> <!-- Spring OAuth2 client only works with Reactor Netty client --> <dependency> <groupId>io.projectreactor.netty</groupId> <artifactId>reactor-netty</artifactId> </dependency> ... <dependencies> ... </project>
-
Create an endpoint controller class for your application:
HelloController.javapackage dev.snowdrop.vertx.sample.http.oauth; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; @RestController public class HelloController { @GetMapping public Mono<String> hello(@AuthenticationPrincipal OAuth2User oauth2User) { return Mono.just("Hello, " + oauth2User.getAttributes().get("name") + "!"); } }Create the main class of your application:
OAuthSampleApplication.javapackage dev.snowdrop.vertx.sample.http.oauth; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class OAuthSampleApplication { public static void main(String[] args) { SpringApplication.run(OAuthSampleApplication.class, args); } }Create a YAML configuration file to store the OAuth2 client ID and client secret you received from GitHub upon registering your application.
src/main/resources/application.ymlspring: security: oauth2: client: registration: github: client-id: YOUR_GITHUB_CLIENT_ID client-secret: YOUR_GITHUB_CLIENT_SECRETOPTIONAL: Run and test your application locally:
Navigate to the root directory of your Maven project:
$ cd myAppPackage your application:
$ mvn clean packageStart your application from the command line:
$ java -jar target/vertx-spring-boot-sample-http-oauth.jar-
Navigate to
http://localhost:8080using a web browser. You are redirected to an OAuth2 application authorization screen on GitHub. If prompted, log in using your GitHub account credentials. - Click Authorize to confirm. You are redirected to a screen showing a personalized greeting message.
Additional resources
- You can deploy your application to an OpenShift cluster using Fabric8 Maven Plugin.
- You can also configure your application for deployment on stand-alone Red Hat Enterprise Linux.
- For more information, see the OAuth2 tutorial in the Spring community documentation. Alternatively, see the tutorial on using OAuth2 with Spring Security.
- For the full OAuth2 authentication framework specification, see document RFC-6749.
Create a reactive SMTP email service with Spring Boot with Eclipse Vert.x.
Prerequisites
- JDK 8 or JDK 11 installed
- Maven installed
- A Maven-based application project configured to use Spring Boot
- A SMTP mail server configured on your machine
Procedure
Add
vertx-spring-boot-starter-httpandvertx-spring-boot-starter-mailas dependencies in thepom.xmlfile of your project.pom.xml<project> ... <dependencies> ... <dependency> <groupId>dev.snowdrop</groupId> <artifactId>vertx-spring-boot-starter-http</artifactId> </dependency> <dependency> <groupId>dev.snowdrop</groupId> <artifactId>vertx-spring-boot-starter-mail</artifactId> </dependency> ... <dependencies> ... </project>Create a mail handler class for your application:
MailHandler.javapackage dev.snowdrop.vertx.sample.mail; import dev.snowdrop.vertx.mail.MailClient; import dev.snowdrop.vertx.mail.MailMessage; import dev.snowdrop.vertx.mail.SimpleMailMessage; import org.springframework.stereotype.Component; import org.springframework.util.MultiValueMap; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; import static org.springframework.web.reactive.function.server.ServerResponse.noContent; @Component public class MailHandler { private final MailClient mailClient; public MailHandler(MailClient mailClient) { this.mailClient = mailClient; } public Mono<ServerResponse> send(ServerRequest request) { return request.formData() .log() .map(this::formToMessage) .flatMap(mailClient::send) .flatMap(result -> noContent().build()); } private MailMessage formToMessage(MultiValueMap<String, String> form) { return new SimpleMailMessage() .setFrom(form.getFirst("from")) .setTo(form.get("to")) .setSubject(form.getFirst("subject")) .setText(form.getFirst("text")); } }Create the main class of your application:
MailSampleApplication.javapackage dev.snowdrop.vertx.sample.mail; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.core.io.ClassPathResource; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerResponse; import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED; import static org.springframework.web.reactive.function.server.RequestPredicates.accept; import static org.springframework.web.reactive.function.server.RouterFunctions.resources; import static org.springframework.web.reactive.function.server.RouterFunctions.route; @SpringBootApplication public class MailSampleApplication { public static void main(String[] args) { SpringApplication.run(MailSampleApplication.class, args); } @Bean public RouterFunction<ServerResponse> mailRouter(MailHandler mailHandler) { return route() .POST("/mail", accept(APPLICATION_FORM_URLENCODED), mailHandler::send) .build(); } @Bean public RouterFunction<ServerResponse> staticResourceRouter() { return resources("/**", new ClassPathResource("static/")); } }Create an
application.propertiesfile to store your SMTP server credentials:application.propertiesvertx.mail.host=YOUR_SMTP_SERVER_HOSTNAME vertx.mail.username=YOUR_SMTP_SERVER_USERNAME vertx.mail.password=YOUR_SMTP_SERVER_PASSWORD-
Create a
src/main/resources/static/index.htmlfile that serves as the frontend of your application. Alternatively, use the example HTML email form available for this procedure. OPTIONAL: Run and test your application locally:
Navigate to the root directory of your Maven project:
$ cd myAppPackage your application:
$ mvn clean packageStart your application from the command line.
$ java -jar target/vertx-spring-boot-sample-mail.jar-
Navigate to
http://localhost:8080/index.htmlusing a web browser to access the email form.
Additional resources
- For more information on setting up an SMTP mail server on RHEL 7, see the Mail Transport Agent Configuration section in the RHEL 7 documentation.
- You can deploy your application to an OpenShift cluster using Fabric8 Maven Plugin
- You can also configure your application for deployment on stand-alone Red Hat Enterprise Linux.
5.7. Server-sent events 复制链接链接已复制到粘贴板!
Server-sent events (SSE) is a push technology allowing HTTP sever to send unidirectional updates to the client. SSE works by establishing a connection between the event source and the client. The event source uses this connection to push events to the client-side. After the server pushes the events, the connection remains open and can be used to push subsequent events. When the client terminates the request on the server, the connection is closed. SSE represents a more resource-efficient alternative to polling, where a new connection must be established each time the client polls the event source for updates. As opposed to WebSockets, SSE pushes events in one direction only (that is, from the source to the client). It does not handle bidirectional communication between the event source and the client.
The specification for SSE is incorporated into HTML5, and is widely supported by web browsers, including their legacy versions. SSE can be used from the command line, and is relatively simple to set up compared to other protocols.
SSE is suitable for use cases that require frequent updates from the server to the client, while updates from the client side to the server are expected to be less frequent. Updates form the client side to the server can then be handled over a different protocol, such as REST. Examples of such use cases include social media feed updates or notifications sent to a client when new files are uploaded to a file server.
Create a simple service that accepts HTTP requests and returns a stream of server-sent events (SSE). When the client establishes a connection to the server and the streaming starts, the connection remains open. The server re-uses the connection to continuously push new events to the client. Canceling the request closes the connection and stops the stream, causing the client to stop receiving updates form the server.
Prerequisites
- JDK 8 or JDK 11 installed
- Maven installed
- A Maven-based application project configured to use Spring Boot
Procedure
Add
vertx-spring-boot-starter-httpas a dependency in thepom.xmlfile of your project.pom.xml<project> ... <dependencies> ... <dependency> <groupId>dev.snowdrop</groupId> <artifactId>vertx-spring-boot-starter-http</artifactId> </dependency> ... <dependencies> ... </project>Create the main class of your application:
SseExampleApplication.javapackage dev.snowdrop.vertx.sample.sse; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SseSampleApplication { public static void main(String[] args) { SpringApplication.run(SseSampleApplication.class, args); } }Create a Server-sent Event controller class for your application. In this example, the class generates a stream of random integers and prints them to a terminal application.
SseController.javapackage dev.snowdrop.vertx.sample.sse; import java.time.Duration; import java.util.Random; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Flux; @RestController public class SseController { @GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<Integer> getRandomNumberStream() { Random random = new Random(); return Flux.interval(Duration.ofSeconds(1)) .map(i -> random.nextInt()) .log(); } }OPTIONAL: Run and test your application locally:
Navigate to the root directory of your Maven project:
$ cd myAppPackage your application:
$ mvn clean packageStart your application from the command line:
$ java -jar target/vertx-spring-boot-sample-sse.jarIn a new terminal window, issue a HTTP request to
localhost. You start receiving a continuous stream of random integers from the server-sent event controller:$ curl localhost:8080 data:-2126721954 data:-573499422 data:1404187823 data:1338766210 data:-666543077 ...Press
Ctrl+Cto cancel your HTTP request and terminate the stream of responses.
Additional resources
- You can deploy your application to an OpenShift cluster using Fabric8 Maven Plugin.
- You can also configure your application for deployment on stand-alone Red Hat Enterprise Linux.
In addition to using an example, you can also use Spring Boot with Eclipse Vert.x starters to create new Spring Boot applications from scratch and deploy them to OpenShift.