Get ahead
VMware offers training and certification to turbo-charge your progress.
Learn moreAn update on the 5th and last milestone of Spring Framework 5.0...
The name *Spring MVC* is both well known and widely used but it may surprise a few there is no actual project or independent distribution with that name. Rather it is a module within the Spring Framework distribution called `spring-webmvc`. Here is another trivia question. Did you know that the top-level package in the module does not feature "mvc"? Rather it is called `org.springframework.web.servlet`. Practically speaking those are details that we don't have to remember. What matters is that we have a short and memorable name to refer to *Spring's Servlet stack based* web framework.
Spring's reactive stack web framework, new in 5.0, is fully reactive and non-blocking. It is suitable for event-loop style processing with a small number of threads. It is supported on Servlet containers (Tomcat, Jetty, Servlet 3.1+) but also non-Servlet runtimes (Netty, Undertow) since the common foundation for this stack is not the Servlet API but a non-blocking alternative built on Reactive Streams and the Reactor project. In case you're wondering, isn't Servlet 3.1 capable of non-blocking I/O? Yes it is and we support running on Servlet 3.1 containers but the rest of the Servlet API is imperative style and can not be used in a reactive, non-blocking stack.
So far we've lacked a dedicated name for the reactive web stack which supports both the Spring MVC annotations (i.e. @Controller
, @RequestMapping
) and a new functional programming model, making it a challenge to discuss and clearly contrast programming models and stacks. In our milestone 5, the spring-web-reactive
module was renamed to spring-webflux
- drawing inspiration, and brevity, from the Flux reactive type at the core of the Spring Web Reactive APIs, with our lower-level reactive HTTP abstractions living in the common spring-web
module. So we now have the spring-webmvc
and the spring-webflux
modules side by side that we'll refer to as Spring (Web)MVC and Spring WebFlux. In case you're wondering: the top-level package in the new module is org.springframework.web.reactive
.
Now for some other key updates in this space...
The `WebClient` is a reactive, non-blocking alternative to the `RestTemplate` adding value for both *reactive* and to *Servlet-stack* applications. It makes it effortless to deal with asynchronous and streaming scenarios.
In M5 we've made substantial improvements eliminating the need for static imports to specify request details and perform an exchange:
WebClient webClient = WebClient.create();
Mono<Person> person = webClient.get()
.uri("http://localhost:8080/persons/42")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.then(response -> response.bodyToMono(Person.class));
If all requests have a comon base URL it can be pre-configured once:
WebClient webClient = WebClient.create("http://localhost:8080");
Mono<Person> person = webClient.get()
.uri("/persons/{id}", 42)
.accept(MediaType.APPLICATION_JSON)
.exchange()
.then(response -> response.bodyToMono(Person.class));
It is also possible to gain programmatic control with a UriBuilder
:
Mono<Person> person = webClient.get()
.uri(builder -> builder.path("/persons/{id}").build("42"))
.accept(MediaType.APPLICATION_JSON)
.exchange()
.then(response -> response.bodyToMono(Person.class));
The new `WebTestClient` in the `spring-test` module forms the basis of the Spring WebFlux integration testing support. It wraps a `WebClient` and exposes an API for integration testing. Similar to `MockMvc` from Spring MVC Test, the new test client does not need an actual, running server and can bind directly to WebFlux server infrastructure using a mock request and response: ````java WebTestClient client = WebTestClient .bindToController(new PersonController()) .build();
client.get().uri("/persons/42") .exchange() .expectStatus().isOk() .expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8) .expectBody(Person.class).value().isEqualTo(new Person("John"));
The new test client however can also run against a live server:
````java
WebTestClient client = WebTestClient
.bindToServer().baseUrl("http://localhost:8080")
.build();
// Same test case...
Streaming is also easy to test possibly using a Reactor StepVerifier
:
FluxExchangeResult<Person> result = client.get().uri("/persons")
.accept(TEXT_EVENT_STREAM)
.exchange()
.expectStatus().isOk()
.expectHeader().contentType(TEXT_EVENT_STREAM)
.expectBody(Person.class)
.returnResult();
StepVerifier.create(result.getResponseBody())
.expectNext(new Person("Jane"), new Person("Jason"))
.expectNextCount(3)
.consumeNextWith(p -> assertEquals("John", p.getName()))
.thenCancel()
.verify();
The M5 release adds a new `PathPatternParser` alternative to the `AntPathMatcher` that enables use of a more efficient parsed pattern representation of request mappings and supports a very handy `"{*foo}" ` URI variable syntax to capture any number of segments at the end of a pattern.
As a first step, a new ParsingPathMatcher
implementation already allows the new PathPatternParser
to be easily plugged into Spring MVC and Spring WebFlux mappings. As a next step towards RC1 the goal is to have a registry of patterns to match against a parsed representation of the request path.
Support for streaming is easy with Spring WebFlux:
````java
@GetMapping(path = "/persons", produces = "text/event-stream")
Flux However what should be done for: We could stream individual JSON objects but that would not be a valid JSON document as a whole and a browser client has no way to consume a stream other than using Server-Sent Events or WebSocket. By default Non-browser clients such as the I'd like to thank everyone who has given Spring Framework 5.0 a try and provided feedback, especially around the new reactive features. Please continue to do that. As always even small comments can prove incredibly valuable as they make us revisit design choices from a different perspective.
If you're reading this from DevNexus this week don't miss the opportunity to see the amazing Josh Long live code a reactive, web application and also the Reactor 3 talk by Simon Baslé, a core member of the Reactor team.@GetMapping("/persons")
Flux<Person> getPersons() {
return this.repository.getPersons();
}
Flux<Person>
will produce a JSON array:[{"name":"Jane"},{"name":"John"},...]
WebClient
can request request content type application/stream+json
and the response will be a stream of JSON objects similar to Server-Sent Events but without the extra formatting:{"name":"Jane"}
{"name":"John"}
...
In Conclusion