Contents


What's new in Spring Framework 5

How Spring 5 leverages Java 8’s functional syntax and a new, reactive programming model

Comments

Released for general availability (GA) in September 2017, Spring 5 marks the first major Spring Framework release since December 2013. It delivers long-awaited improvements and adopts a new programing paradigm based on reactive principles set out in the reactive manifesto.

This release is by far the most exciting release of the Spring Framework for a long while. Compatible with Java™ 8 and JDK 9, Spring 5 integrates reactive streams for a game-changing approach to endpoint and web application development.

Indeed, reactive programming is the theme for this release, and is the headline feature that has many developers fired up. It fits neatly into the growing requirement for resilient and responsive services that scale seamlessly for a fluctuating load.

This article presents a 30,000-foot view of Spring 5. I introduce baseline upgrades to Java SE 8 and Java EE 7 APIs, Spring 5’s new reactive programming model, HTTP/2 support, and Spring’s full support for functional programming with Kotlin. I also touch briefly on testing and performance enhancements, and conclude with general revisions to the Spring core and container.

Upgrade to Java SE 8 and Java EE 7

Until now, the Spring Framework has supported deprecated Java releases, but Spring 5 is liberated from that legacy baggage. Its codebase has been revamped to take advantage of Java 8 features, and the framework requires Java 8 as a minimum JDK version.

Spring 5 is fully compatible with Java 9 on the classpath, as well as the module path, and it passes the JDK 9 test suite. This is welcome news for Java 9 fans, as Spring will be ready to run with Java 9 as soon as it's released.

At the API level, Spring 5 is compatible with Java EE 8 technologies and meets the requirements for Servlet 4.0, Bean Validation 2.0, and the brand-new JSON Binding API. The minimum requirement for Java EE APIs is version 7, which introduced minor version releases for the Servlet, JPA, and Bean Validation APIs.

Reactive programming model

Spring 5’s most exciting new feature is its reactive programming model. The Spring 5 framework is built on a reactive foundation and is fully asynchronous and nonblocking. The new event-loop execution model can scale vertically with only a small number of threads.

The framework adopts reactive streams to provide a mechanism for communicating backpressure in a pipeline of reactive components. Backpressure is a concept that ensures consumers do not get overwhelmed with data coming from multiple producers.

Spring WebFlux, Spring 5’s reactive core, offers developers two programming models designed for Spring web programming: an annotation-based model and the Functional Web Framework (WebFlux.fn).

The annotation-based model is the modern alternative to Spring WebMVC and is built on reactive foundations, while the Functional Web Framework is the alternative to the @Controller annotation-based programming model. The models run over the same reactive base, which adapts non-blocking HTTP to the reactive streams API.

Programming with annotations

Spring 5’s annotation-based programming model should feel very familiar to WebMVC programmers. Spring 5 has adapted WebMVC’s @Controller programming model and employs the same annotations.

In Listing 1 the BookController class presents two method that respond to HTTP requests for a list of books and a book with the given id. Note the objects returned by the resource methods, Mono and Flux. These are reactive types that implement the Publisher interface from the reactive streams specification. Their role is to deal with streams of data. The Mono object deals with a stream of one element, while Flux represents a stream of N elements.

Listing 1. Reactive controller
@RestController
public class BookController {

	@GetMapping("/book")
	Flux<Book> list() {
		return this.repository.findAll();
	}

	@GetMapping("/book/{id}")
	Mono<Book> findById(@PathVariable String id) {
		return this.repository.findOne(id);
	}

    // Plumbing code omitted for brevity
}

That’s annotations for Spring web programming. Now let’s solve the same problem using the functional web framework.

Functional programming

Spring 5’s new functional approach delegates requests to handler functions, which accept a server request instance and return a reactive type. This is demonstrated in Listing 2, where the listBook and getBook methods echo the functionality from Listing 1.

Listing 2. Listing 2. BookHandler function class
public class BookHandler {

    public Mono<ServerResponse> listBooks(ServerRequest request) {
        return ServerResponse.ok()
            .contentType(APPLICATION_JSON)
            .body(repository.allPeople(), Book.class);
    }
    
    public Mono<ServerResponse> getBook(ServerRequest request) {
        return repository.getBook(request.pathVariable("id"))
            .then(book -> ServerResponse.ok()
            .contentType(APPLICATION_JSON)
            .body(fromObject(book)))
            .otherwiseIfEmpty(ServerResponse.notFound().build());
    }
    // Plumbing code omitted for brevity
}

Client requests are routed to the handler via routing functions that match HTTP request predicates and media types. Listing 3 shows the book resource endpoint URI delegating calls to the appropriate handler function:

Listing 3. Router functions
BookHandler handler = new BookHandler();

RouterFunction<ServerResponse> personRoute =
    route(
        GET("/books/{id}")
        .and(accept(APPLICATION_JSON)), handler::getBook)
        .andRoute(
    GET("/books")
        .and(accept(APPLICATION_JSON)), handler::listBooks);

The data repository behind these examples also supports the full reactive experience via Spring Data’s support for reactive Couchbase, Reactive MongoDB, and Cassandra.

Reactive-style programming with REST endpoints

The new programming model is a departure from the traditional Spring WebMVC model and brings with it some very nice new features.

For one, the WebFlux module offers a fully non-blocking and reactive alternative to the RestTemplate, called WebClient. Listing 4 creates a WebClient and calls the books endpoint to request a book with the given id of 1234.

Listing 4. Call REST endpoint with WebClient
Mono<Book> book = WebClient.create("http://localhost:8080")
      .get()
      .url("/books/{id}", 1234)
      .accept(APPLICATION_JSON)
      .exchange(request)
      .then(response -> response.bodyToMono(Book.class));

HTTP/2 support

Spring Framework 5.0 will ship with dedicated HTTP/2 features support, as well as support for the new HTTP client expected in JDK 9. While HTTP/2’s server push feature has been available to Spring developers for quite some time through Jetty servlet engine’s ServerPushFilter class, Web optimizers will be jumping with joy to find HTTP/2 performance enhancements available out of the box in Spring 5.

The Java EE Servlet specification is expected for release in the last quarter of 2017, and Servlet 4.0 support goes live in Spring 5.1. Until then, HTTP/2 features will be provided natively by Tomcat 9.0, Jetty 9.3, and Undertow 1.4.

Kotlin and Spring WebFlux

Kotlin is an object-oriented language from JetBrains that supports functional programming. One of its principal strengths is that it provides very good interoperability with Java. Spring embraces this wholeheartedly in version 5, by introducing dedicated support for Kotlin. Its functional programming style is the ideal match for the Spring WebFlux module, and its new routing DSL leverages the functional web framework with clean and idiomatic code. Endpoint routing can be expressed as simply as shown in Listing 5:

Listing 5. Kotlin’s routing DSL used to define endpoints
    @Bean
    fun apiRouter() = router {
        (accept(APPLICATION_JSON) and "/api").nest {
            "/book".nest {
                GET("/", bookHandler::findAll)
                GET("/{id}", bookHandler::findOne)
            }
			"/video".nest {
                GET("/", videoHandler::findAll)
                GET("/{genre}", videoHandler::findByGenre)
            }
		}
	}

Support for Kotlin’s immutable classes with optional parameters with default values and full null-safe APIs has been added, when using Kotlin 1.1.4+.

Lambdas for bean registration

It’s now possible to register a Spring bean using lambdas as an alternative to traditional XML and JavaConfig, so that beans are effectively registered as suppliers. Listing 6 registers a Book bean using lambdas.

Listing 6. Bean registered as a supplier
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean(Book.class, () -> new 
		      Book(context.getBean(Author.class))
		);

Spring WebMVC support for latest APIs

The shiny new WebFlux module offers many new and exciting capabilities, but Spring 5 also caters to developers who prefer to continue using Spring MVC. The model-view-controller framework in Spring 5 has been updated to work with WebFlux and the latest versions of Jackson 2.9 and Protobuf 3.0, and even includes support for the new Java EE 8 JSON-Binding API.

In addition to the underlying server implementation of HTTP/2 features, Spring WebMVC also supports Servlet 4.0’s PushBuilder via an argument to the MVC controller methods. Finally, WebMVC includes full support for the Reactor 3.1 Flux and Mono objects, as well as RxJava 1.3 and 2.1, which are treated as return values from MVC controller methods. This support targets the new reactive WebClient and reactive repositories in Spring Data.

Conditional and concurrent testing with JUnit 5

Spring 5’s test suite is enhanced in several ways, but most notably by its support for JUnit 5. You can now leverage functional programming features found in Java 8 in your unit tests. Listing 7 demonstrates:

Listing 7. Listing 7. JUnit 5 fully embraces Java 8 streams and lambdas
@Test
void givenStreamOfInts_SumShouldBeMoreThanFive() {
    assertTrue(Stream.of(20, 40, 50)
      .stream()
      .mapToInt(i -> i)
      .sum() > 110, () -> "Total should be more than 100");
}

Spring 5 embraces JUnit 5’s flexibility to implement multiple extension APIs within the Spring TestContext Framework. As an example, developers can use JUnit 5’s conditional test execution annotations @EnabledIf and @DisabledIf to automatically evaluate a SpEL (Spring Expression Language) expression, and enable or disable a test as appropriate. With these annotations, Spring 5 supports sophisticated conditional testing scenarios that previously have been difficult to achieve. The Spring TextContext Framework is now able to execute tests concurrently.

Integration testing with Spring WebFlux

Spring Test now includes a WebTestClient that supports integration testing of Spring WebFlux server endpoints. WebTestClient uses mock requests and responses to avoid running up a server, and is able to bind directly to the WebFlux server infrastructure.

WebTestClient can be bound to a real server or work with controllers or functions. In Listing 8, WebTestClient is bound to the localhost:

Listing 8. WebTestClient bound to the localhost
WebTestClient testClient = WebTestClient
  .bindToServer()
  .baseUrl("http://localhost:8080")
  .build();

In Listing 9, a RouterFunction is tested:

Listing 9. Bind WebTestClient to a RouterFunction
RouterFunction bookRouter = RouterFunctions.route(
  RequestPredicates.GET("/books"),
  request -> ServerResponse.ok().build()
);
 
WebTestClient
  .bindToRouterFunction(bookRouter)
  .build().get().uri("/books")
  .exchange()
  .expectStatus().isOk()
  .expectBody().isEmpty();

Package cleansing and deprecation

Spring 5 discontinues support for a handful of out-of-date APIs. Caught up in the cull are Hibernate 3 and 4, which have been dropped in favor of Hibernate 5. Also gone is support for Portlet, Velocity, JasperReports, XMLBeans, JDO, and Guava.

The spring cleaning continues at the package level: Spring 5 no longer supports beans.factory.access, jdbc.support.nativejdbc, mock.staticmock (from the spring-aspects module), or web.view.tiles2M. Tiles 3 is now the minimum requirement for Spring.

General updates to the Spring core and container

Spring Framework 5 improves the way components are scanned and identified, resulting in performance enhancements for large projects. Scanning now happens at compile-time and component candidates are added to an index file located in the META-INF/spring.components file. The index is generated by a platform-specific application build task defined for the project.

Components marked with an annotation from the javax package are added to the index, along with any class or interface annotated with @Index. Spring’s traditional classpath scanning has not been removed but remains as a fallback option. There is a clear performance benefit for large code bases, while servers hosting many Spring projects will see a reduction in startup times.

Spring 5 also adds support for @Nullable, which can be used to indicate optional injection points. The consumer must now be ready to accept a null value. In addition, this annotations can be used to mark nullable arguments, fields, and return values. Targeted primarily for use with IDEs such as IntelliJ IDEA, but also Eclipse and FindBugs, @Nullable facilitates the handling of null values at compile time, rather than sending NullPointerExceptions at runtime.

Spring Logging also gets a boost, with its own Commons Logging bridge right out of the box. Defensive programming is now supported by the Resource abstraction, providing an isFile indicator for getFile access.

Conclusion

Spring 5’s headline feature is the new reactive programming model, which represents a big commitment to providing responsive Spring-based services that scale seamlessly. With Spring 5 adoption, developers can expect to see reactive programming further entrenched as the path forward for web and enterprise application development in Java.

Future Spring Framework releases will continue to reflect this commitment, as Spring Security, Spring Data, and Spring Integration are expected to adopt characteristics and strengths of reactive programming.

All in all, Spring 5 represents a welcome paradigm shift for Spring-based developers, and handily points the way for other frameworks to follow.


Downloadable resources


Related topics


Comments

Sign in or register to add and subscribe to comments.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java development, Open source
ArticleID=1049960
ArticleTitle=What's new in Spring Framework 5
publish-date=09192017