Spring 5于2017年9月发布了通用版本,它是自2013年12月以来第一个主要的Spring版本。它提供了一些人们期待已久的改进,还采用了一种全新的编程范例,以反应式原则为基础。
这个版本是很长时间以来最令人激动的版本。Spring 5兼容Java?8和JDK 9,它集成了反应式流,以方便后续提供一种颠覆性方法来实现端点和Web应用程序开发。
当然,反应式编程不仅是此版本的主题,还是令许多程序员激动不已的重大特性。人们对能够针对负载波动进行无缝扩展的容灾和响应式服务的需求在不断增加,Spring 5很好地满足了这一需求。
下面介绍Java SE 8和Java EE 7 API升级的基本内容、Spring 5的新反应式编程模型、对HTTP/2的支持,以及Spring通过Kotlin对函数式编程的全面支持。还会简要介绍测试和性能增强,最后介绍对Spring核心和容器的一般性修订。
20.1 升级到Java SE 8和Java EE 7
以前的Spring一直在支持一些弃用的Java版本,而Spring 5已从“旧包袱”中解放出来。为了充分利用Java 8的特性,它的代码库已进行了改进,而且要求将Java 8作为最低的JDK版本。
Spring 5在类路径(和模块路径)上完全兼容Java 9,而且它通过了JDK 9测试套件的测试。对Java 9爱好者而言,这是一个好消息。
在API级别上,Spring 5兼容Java EE 8技术,满足对Servlet 4.0、Bean Validation 2.0和全新的JSON Binding API的需求。对Java EE API的最低要求为V7,该版本引入了针对Servlet、JPA和Bean Validation API的次要版本。
20.2 反应式编程模型
Spring 5最令人兴奋的新特性是它的反应式编程模型。Spring 5基于一种反应式基础而构建,而且是完全异步和非阻塞的。只需少量的线程,新的事件循环执行模型就可以垂直扩展。
Spring 5采用反应式流来提供在反应式组件中传播负压的机制。负压是一个确保来自多个生产者的数据不会让使用者不堪重负的概念。
Spring WebFlux是Spring 5的反应式核心,它为开发人员提供了两种为Spring Web编程而设计的编程模型:基于注解的模型和Functional Web Framework(WebFlux.fn)。
基于注解的模型是Spring Web MVC的现代替代方案,该模型基于反应式基础而构建,而Functional Web Framework是基于@Controller注解的编程模型的替代方案。这些模型都通过同一种反应式规则来运行,后者调整非阻塞HTTP来适应反应式流API。
20.3 使用注解进行编程
Web MVC程序员应该对Spring 5的基于注解的编程模型非常熟悉,Spring 5调整了Web MVC的@Controller编程模型,采用了相同的注解。
在下面的代码中BookController类提供了两个方法,分别响应针对某个图书列表的HTTP请求,以及针对具有给定id的图书的HTTP请求。请注意Mono和Flux等对象。这些对象是实现反应式流规范中的Publisher接口的反应式类型,它们的职责是处理数据流。Mono对象处理一个仅含1个元素的流,而Flux表示一个包含N个元素的流。
@RestController
public class BookController { //反应式控制器
@GetMapping("/book")
Flux list() {
return this.repository.findAll();
}
@GetMapping("/book/{id}")
Mono findById(@PathVariable String id) {
return this.repository.findOne(id);
}
}
以上是针对Spring Web编程的注解,下面我们使用函数式Web框架来解决同一个问题。
20.4 函数式编程
Spring 5的函数式方法将请求委托给处理函数,这些函数接收一个服务器请求实例并返回一种反应式类型。来看一段代码,创建BookHandler类,其中listBooks()和getBook()方法相当于Controller中的功能。
public class BookHandler {
public Mono listBooks(ServerRequest request) {
return ServerResponse.ok()
.contentType(APPLICATION_JSON)
.body(repository.allPeople(), Book.class);
}
public Mono getBook(ServerRequest request) {
return repository.getBook(request.pathVariable("id"))
.then(book -> ServerResponse.ok()
.contentType(APPLICATION_JSON)
.body(fromObject(book)))
.otherwiseIfEmpty(ServerResponse.notFound().build());
}
}
通过路由函数来匹配HTTP请求参数与媒体类型,将客户端请求路由到处理函数。下面的代码展示了图书资源端点URI将调用委托给合适的处理函数:
BookHandler handler = new BookHandler();
RouterFunction personRoute =
route(
GET("/books/{id}")
.and(accept(APPLICATION_JSON)), handler::getBook)
.andRoute(
GET("/books")
.and(accept(APPLICATION_JSON)), handler::listBooks);
这些示例背后的数据存储也支持完整的反应式体验,该体验是通过Spring Data对反应式 Couchbase、Reactive MongoDB和Cassandra的支持来实现的。
20.5 使用 REST 端点执行反应式编程
新的编程模型脱离了传统的Spring Web MVC模型,引入了一些很不错的新特性。
举例来说,WebFlux模块为RestTemplate提供了一种完全非阻塞、反应式的替代方案,名为WebClient。下面创建一个WebClient,并调用books端点来请求一本给定id为1234的图书。
//通过WebClient调用REST端点
Mono book = WebClient.create("http://localhost:8080")
.get()
.url("/books/{id}", 1234)
.accept(APPLICATION_JSON)
.exchange(request)
.then(response -> response.bodyToMono(Book.class));
20.6 支持HTTP/2
HTTP/2提高了传输性能,减少了延迟,并提高了应用程序的吞吐量,从而提供了丰富的Web体验。
Spring 5提供专门的HTTP/2特性支持,还支持人们期望出现在JDK 9中的新HTTP客户端。尽管HTTP/2的服务器推送功能已通过Jetty Servlet引擎的ServerPushFilter类向Spring开发人员公开很长一段时间了,但如果发现Spring 5中开箱即用地提供了HTTP/2性能增强,Web优化者们一定会为此欢呼雀跃。
Spring 5.1提供Servlet 4.0,HTTP/2新特性将由Tomcat 9.0、Jetty 9.3和Undertow 1.4原生提供。
20.7 Kotlin和Spring WebFlux
(其他特性详细说明请见原书…………)
……
展开
本书是基于Spring 5开发的架构师实战指南,几乎涵盖在Spring应用中可能遇到的所有问题,包括核心原理(IOC、DI、AOP、MVC)、高仿手写、数据访问等。
——James
咕泡学院联合创始人
如果你想成为架构师,恭喜你遇到了这本书;如果你不想成为架构师,请把本书介绍给需要的人。
——Mic
咕泡学院联合创始人