Reactive Web with Spring 5
Aug 1, 2016
2 minute read

Last week the first milestone of Spring Framework 5 was released which includes initial support for reactive programming. (See official post )

This blog post is a hands on Spring Reactive Web with a minimal Spring Boot example. While the mentioned post at spring.io suggests using the start.spring.io site to test the experimental reactive web starter, I could not just import the generated project and start coding. When I imported the gradle project into IntelliJ, it crashed, throwing an exception Error:Cause: org.gradle.internal.component.external.model.DefaultModuleComponentSelector and the Maven counterpart would not download the dependencies.

To fix that I had to add the milestone spring repository as well as change the spring and reactor versions from SNAPSHOT to M1/RC1 in the pom file.

<reactor.version>3.0.0.RC1</reactor.version>
<spring.version>5.0.0.M1</spring.version>

<repositories>
    <repository>
        <id>spring-snapshots</id>
        <url>http://repo.spring.io/snapshot</url>
        <snapshots><enabled>true</enabled></snapshots>
    </repository>
    <repository>
        <id>spring-milestones</id>
        <url>http://repo.spring.io/milestone</url>
    </repository>
</repositories>
<pluginRepositories>
    <pluginRepository>
        <id>spring-snapshots</id>
        <url>http://repo.spring.io/snapshot</url>
    </pluginRepository>
    <pluginRepository>
        <id>spring-milestones</id>
        <url>http://repo.spring.io/milestone</url>
    </pluginRepository>
</pluginRepositories>

Next i excluded tomcat and imported netty to also test the new reactive WebClient support.

<dependency>
    <groupId>org.springframework.boot.experimental</groupId>
    <artifactId>spring-boot-starter-web-reactive</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>io.projectreactor.ipc</groupId>
    <artifactId>reactor-netty</artifactId>
</dependency>

Now we can finally write our hello world controller in kotlin. (Refer to projectreactor for more information on Flux and Mono.)

@RestController
class HelloController {

    data class Person(val name: String)

    @GetMapping("/hello")
    fun hello(): Mono<String> {
        return Mono.just("Hello World!")
    }

    @GetMapping("/all")
    fun all(): Flux<Person> {
        return Flux.just(Person("Artur"), Person("Chris"))
    }

}

We can visit the /all and /hello endpoints to view the output as json in the browser. Here we use the new reactive web client to get the result as Mono’s. Notice that we use response.block() to wait for the result.

class HelloControllerTest {

@Test
fun test() {
    val httpConnector = ReactorClientHttpConnector()
    val webClient = WebClient(httpConnector)

    val responseString = webClient.perform(ClientWebRequestBuilders.get("http://localhost:8888/hello")
            .accept(MediaType.APPLICATION_JSON)).extract(ResponseExtractors
            .body(String::class.java))

    val responseJson = webClient.perform(ClientWebRequestBuilders.get("http://localhost:8888/all")
            .accept(MediaType.APPLICATION_JSON)).extract(ResponseExtractors
            .body(String::class.java))

    println(responseString.block(Duration.ofSeconds(1L)))
    println(responseJson.block(Duration.ofSeconds(1L)))
}
    
}

For more information on reactive web please visit the official documentation