Spring Boot Functional Endpoints
Welcome, in this tutorial, we will see how to create functional endpoints in a spring boot reactive application.
1. Introduction
Before going further in this tutorial, let us understanding web flux and reactive programming.
1.1 Webflux
- Webflux is the reactive-web framework in spring and was added as a part of the 5.0 release
- It offers asynchronous, non-blocking, and event-driven approach for the data processing
- It also offers reactive streams back-pressure and runs on servers like Netty, Undertow, or the Servlet 3.1 containers
1.2 Reactive programming
- Reactive programming is a functional, event-based, asynchronous, non-blocking data processing technique
- The programming technique refers to reacting to the changes such as mouse clicks or the I/O events
- The reactive programming application works better and more efficiently when working with the stream of data. The client application consumes it and streams it back to the users
- The streaming api provides 4 different interfaces –
Publisher
– Emits a sequence of events to subscribers according to the subscriber demandsSubscriber
– Receives and processes the events emitted by the publisher interface. Multiple subscribers can be linked to a single publisher and can respond differently to the same eventSubscription
– Defines a 1-1 relationship between the publisher and subscriber interfaces. Each subscriber can only be linked to a single publisherProcessor
– Shows a processing stage consisting of both subscriber and publisher interface. It also obeys the contract of both the interfaces
1.3 Spring Webflux
- Spring Webflux is similar to spring MVC and supports non-blocking reactive streams. It also supports the back-pressure concept and uses Netty as the preferred server to run reactive applications
- Uses the project reactor as the reactive library
- It uses 2 publishers –
Mono
returns 0 or 1 elementFlux
returns 0 to N elements. It is endless and can emit events forever. It also sends a complete notification when the last event is sent
- Spring webflux allows scalability and immunity to latency problems in a microservice architecture. It also offers excellent stream processing capabilities
1.4 Lombok
- Lombok is nothing but a small library that reduces the amount of boilerplate Java code from the project
- Automatically generates the getters and setters for the object by using the Lombok annotations
- Hooks in via the Annotation processor API
- Raw source code is passed to Lombok for code generation before the Java Compiler continues. Thus, produces properly compiled Java code in conjunction with the Java Compiler
- Under the
target/classes
folder you can view the compiled class files - Can be used with Maven, Gradle IDE, etc.
1.4.1 Lombok features
Feature | Details |
---|---|
val | Local variables are declared as final |
var | Mutable local variables |
@Slf4J | Creates an SLF4J logger |
@Cleanup | Will call close() on the resource in the finally block |
@Getter | Creates getter methods for all properties |
@Setter | Creates setter for all non-final properties |
@EqualsAndHashCode |
|
@ToString |
|
@NoArgsConstructor |
|
@RequiredArgsContructor |
|
@AllArgsConstructor |
|
@Data |
|
@Builder |
|
@Value |
|
2. Spring Boot Functional Endpoints
Let us go ahead with the tutorial implementation but before going any further I’m assuming that you’re aware of the Spring boot basics.
2.1 Tools Used for Spring boot application and Project Structure
We are using Eclipse Kepler SR2, JDK 8, and Maven. In case you’re confused about where you should create the corresponding files or folder, let us review the project structure of the spring boot application.
Let us start building the application!
3. Creating a Spring Boot application
Below are the steps involved in developing the application.
3.1 Maven Dependency
Here, we specify the dependency for the Spring boot (Webflux) and Lombok. The updated file will have the following code.
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.5</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.springboot</groupId> <artifactId>SpringbootFunctionalrouting</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <java.version>1.8</java.version> </properties> <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> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
3.2 Application properties file
Create a new YML file at the location: SpringbootFunctionalrouting/src/main/resources/
and add the following code. You’re free to change the application details as per your wish.
application.properties
server.port=9091 spring.application.name=springboot-functional-routing
3.3 Java Classes
Let us write the important java class(es) involved in this application.
3.3.1 Implementation/Main class
Add the following code to the main class to bootstrap the application from the main method. Always remember, the entry point of the spring boot application is the class containing @SpringBootApplication
annotation and the static main method.
SpringbootFunctionalroutingApplication.java
package com.springboot.flux; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; //lombok annotation @Slf4j //spring annotation @SpringBootApplication public class SpringbootFunctionalroutingApplication { public static void main(String[] args) { SpringApplication.run(SpringbootFunctionalroutingApplication.class, args); log.info("Spring boot and functional routing application started successfully"); } }
3.3.2 Handler class
Add the following code to the handler class. The handler methods will map to the endpoints defined in the router class.
MyHandler.java
package com.springboot.flux.handler; import lombok.extern.slf4j.Slf4j; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.time.Duration; //lombok annotation @Slf4j //spring annotation @Component public class MyHandler { //serves a plain text public Mono<ServerResponse> returnMonoResponse() { log.info("Returning a plain text"); return ServerResponse.ok() .contentType(MediaType.TEXT_PLAIN) .body(Mono.just("Welcome to javacodegeeks.com"), String.class); } //serves a json stream public Mono<ServerResponse> returnFluxResponse() { log.info("Returning a json stream"); return ServerResponse.ok() .contentType(MediaType.TEXT_EVENT_STREAM) .body(Flux.just("Welcome", "to", "javacodegeeks.com") .delayElements(Duration.ofSeconds(2)) .log(), String.class); } //serves a json stream public Mono<ServerResponse> returnUserFluxResponse(final ServerRequest request) { final String name = request.pathVariable("name"); log.info("Returning a username stream for = {}", name); return ServerResponse.ok() .contentType(MediaType.TEXT_EVENT_STREAM) .body(Flux.just("Welcome", name, "to", "javacodegeeks.com") .delayElements(Duration.ofSeconds(2)) .log(), String.class); } }
3.3.3 Router class
Add the following code to the router class. In this class, we will define the router function that maps to the respective handler functions.
MyRoutes.java
package com.springboot.flux.routes; import com.springboot.flux.handler.MyHandler; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.reactive.function.server.ServerResponse; //spring annotation @Configuration public class MyRoutes { //spring annotation @Bean public RouterFunction<ServerResponse> functionalRoutes(final MyHandler handler) { return RouterFunctions.route() .GET("/api/mono", request -> handler.returnMonoResponse()) // http://localhost:9091/api/mono .GET("/api/flux", request -> handler.returnFluxResponse()) // http://localhost:9091/api/flux .GET("/user/flux/{name}", handler::returnUserFluxResponse) // http://localhost:9091/user/flux/daniel .build(); } }
4. Run the Application
To execute the application, right-click on the SpringbootFunctionalroutingApplication.java
class, Run As -> Java Application
.
5. Project Demo
When the application is started we can test the mono and flux endpoints. To test the mono endpoint, open the below URL in the browser.
Mono endpoint
http://localhost:9091/api/mono
You will get a message – Welcome to javacodegeeks.com
on the browser. Similarly, test the flux endpoint, open the below URL in the browser.
Flux endpoint
http://localhost:9091/api/flux
You will get the message – Welcome to javacodegeeks.com
printed on the browser in parts. The message is received in parts as a JSON stream after 2 seconds with the help of a flux stream. Similarly, you can hit the name
endpoint to receive the welcome message as a flux stream. That is all for this tutorial and I hope the article served you whatever you were looking for. Happy Learning and do not forget to share!
6. Summary
In this section, you learned:
- Introduction to Webflux, Reactive programming, Spring Webflux, and Lombok
- Steps to implement functional routing in a spring boot reactive application
You can download the sample application as an Eclipse project in the Downloads section.
7. Download the Project
This was an example of how to create functional endpoints in a spring boot reactive application.
You can download the full source code of this example here: Spring Boot Functional Endpoints