最近,有一个小伙伴拿到了自己满意的Offer,和他交谈的过程中得知他面试官问他关于Spring的问题比较多,其中最让面试官满意的就是自己回答关于Spring 5的知识点回答的不错。

Spring5于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核心和容器的一般性修订。

升级到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的次要版本。

反应式编程模型

Spring 5最令人兴奋的新特性是它的反应式编程模型。Spring 5基于一种反应式基础而构建,而且是完全异步和非阻塞的。只需少量的线程,新的事件循环执行模型就可以垂直扩展。

Spring 5采用反应式流来提供在反应式组件中传播负压的机制。负压是一个确保来自多个生产者的数据不会让使用者不堪重负的概念。

Spring WebFlux是Spring 5的反应式核心,它为开发人员提供了两种为Spring Web编程而设计的编程模型:基于注解的模型和Functional WebFramework(WebFlux.fn)。

基于注解的模型是Spring Web MVC的现代替代方案,该模型基于反应式基础而构建,而Functional Web Framework是基于@Controller注解的编程模型的替代方案。这些模型都通过同一种反应式规则来运行,后者调整非阻塞HTTP来适应反应式流API。

使用注解进行编程

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<Book> list() {
returnthis.repository.findAll();
}
@GetMapping("/book/{id}")
Mono<Book> findById(@PathVariable String id) {
returnthis.repository.findOne(id);
}
}

以上是针对Spring Web编程的注解,下面我们使用函数式Web框架来解决同一个问题。

函数式编程

Spring 5的函数式方法将请求委托给处理函数,这些函数接收一个服务器请求实例并返回一种反应式类型。来看一段代码,创建BookHandler类,其中listBooks()和getBook()方法相当于Controller中的功能。

publicclassBookHandler {
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());
}
}

通过路由函数来匹配HTTP请求参数与媒体类型,将客户端请求路由到处理函数。下面的代码展示了图书资源端点URI将调用委托给合适的处理函数:

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);

这些示例背后的数据存储也支持完整的反应式体验,该体验是通过Spring Data对反应式 Couchbase、Reactive MongoDB和Cassandra的支持来实现的。

使用 REST 端点执行反应式编程

新的编程模型脱离了传统的Spring Web MVC模型,引入了一些很不错的新特性。

举例来说,WebFlux模块为RestTemplate提供了一种完全非阻塞、反应式的替代方案,名为WebClient。下面创建一个WebClient,并调用books端点来请求一本给定id为1234的图书。

//通过WebClient调用REST端点
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

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、Jetty9.3和Undertow 1.4原生提供。

Kotlin和Spring WebFlux

Kotlin是一种来自JetBrains的面向对象语言,支持函数式编程。它的主要优势之一是与Java有非常高的互操作性。通过引入对Kotlin的专门支持,Spring 5全面吸纳了这一优势。它的函数式编程风格与Spring WebFlux模块完美匹配,它的新路由DSL利用了函数式Web框架及干净且符合语言习惯的代码。可以像下面代码中这样简单地表达端点路由:

//Kotlin用于定义端点的路由DSL
@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)
}
}
}

使用Kotlin 1.1.4以上版本时,还添加了对Kotlin的不可变类的支持(通过带默认值的可选参数),以及对完全支持null的API的支持。

使用Lambda表达式注册Bean

作为传统XML和JavaConfig的替代方案,现在可以使用Lambda表达式注册Spring Bean,使Bean可以实际注册为提供者。下面代码中使用Lambda表达式注册了一个Book Bean:

GenericApplicationContext context = newGenericApplicationContext();
context.registerBean(Book.class, () ->new
Book(context.getBean(Author.class))
);

Spring Web MVC支持最新的 API

全新的WebFlux模块提供了许多新的、令人兴奋的功能,但Spring 5也迎合了愿意继续使用 Spring MVC的开发人员的需求。Spring 5中更新了“模型-视图-控制器”框架,以兼容WebFlux和最新版的Jackson 2.9和Protobuf 3.0,甚至包括对新的Java EE 8 JSON-Binding API的支持。

除了HTTP/2特性的基础服务器实现,Spring Web MVC还通过MVC控制器方法的一个参数来支持Servlet 4.0 的PushBuilder。最后,Web MVC全面支持Reactor 3.1的Flux和Mono对象,以及RxJava 1.3和RxJava 2.1,它们被视为来自MVC控制器方法的返回值。这项支持的最终目的是支持Spring Data中新的反应式WebClient和反应式存储库。

使用JUnit 5执行条件和并发测试

1. JUnit和Spring 5

Spring5全面接纳了函数式范例,并支持JUnit5及其新的函数式测试风格。还提供了对JUnit 4的向后兼容性,以确保不会破坏旧代码。

Spring5的测试套件通过多种方式得到了增强,但最明显的是它对JUnit 5的支持。现在可以在单元测试中利用Java 8中提供的函数式编程特性。以下代码演示了这一支持:

@Test
void givenStreamOfInts_SumShouldBeMoreThanFive() {
assertTrue(Stream.of(20, 40, 50)
.stream()
.mapToInt(i -> i)
.sum() > 110, () -> "Total should be more than 100");
}

2. 迁移到JUnit 5

如果你对升级到JUnit 5持观望态度,StevePerry的分两部分的深入剖析教程将说服你进行尝试。

Spring5继承了JUnit 5在Spring TestContext Framework内实现多个扩展API的灵活性。举例,开发人员可以使用JUnit 5的条件测试执行注解@EnabledIf和@DisabledIf来自动计算一个SpEL(Spring Expression Language)表达式,并适当地启用或禁用测试。借助这些注解,Spring 5支持以前很难实现的复杂的条件测试方案。SpringTextContext Framework现在能够并发执行测试。

3. 使用 Spring WebFlux 执行集成测试

Spring Test现在包含一个WebTestClient,后者支持对Spring WebFlux服务器端点执行集成测试。WebTestClient使用模拟请求和响应来避免耗尽服务器资源,并能直接绑定到WebFlux服务器的基础架构。

WebTestClient可绑定到真实的服务器,或者使用控制器或函数。在下面的代码中,WebTestClient被绑定到localhost:

WebTestClient testClient = WebTestClient
.bindToServer()
.baseUrl("http://localhost:8080")
.build();

下面的代码将WebTestClient绑定到RouterFunction:

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

包清理和弃用

Spring5终止了对一些过时API的支持。遭此厄运的有Hibernate 3和Hibernate 4,为了支持Hibernate 5,它们遭到了弃用。另外,对Portlet、Velocity、JasperReports、XMLBeans、JDO和Guava的支持也已终止。

包级别上的清理工作仍在继续。Spring 5不再支持beans.factory.access、jdbc.support.nativejdbc、mock.staticmock(来自spring-aspects模块)或web.view.tiles2M。Tiles 3现在是Spring的最低要求。

Spring核心和容器的一般更新

Spring 5改进了扫描和识别组件的方法,使大型项目的性能得到提升。目前,扫描是在编译时执行的,而且向META-INF/spring.components文件中的索引文件添加了组件坐标。该索引是通过一个为项目定义的特定于平台的应用程序构建任务来生成的。

标有来自javax包的注解的组件会添加到索引中,任何带@Index注解的类或接口都会添加到索引中。Spring的传统类路径扫描方式没有被删除,而是保留下来作为一种后备选择。有许多针对大型代码库的明显性能优势,托管许多Spring项目的服务器也会缩短启动时间。

Spring 5还添加了对@Nullable的支持,后者可用于指示可选的注入点。使用者现在必须准备接受null值。此外,还可以使用此注解来标记可以为null的参数、字段和返回值。@Nullable主要用于IntelliJ IDEA等IDE,但也可用于Eclipse和FindBugs,它使得在编译时处理null值变得更方便,无须在运行时发送NullPointerExceptions。

Spring Logging还提升了性能,自带开箱即用的Commons Logging桥接器。现在已通过资源抽象支持防御性编程,为getFile访问提供了isFile指示器。

我如何看Spring 5

Spring 5的首要特性是新的反应式编程模型,这代表着对提供可无缝扩展、基于Spring的响应式服务的重大保障。随着人们对Spring 5的采用,反应式编程有望成为使用Java语言的Web和企业应用程序开发的未来。

未来的Spring将继续体现这一承诺,因为SpringSecurity、Spring Data和Spring Integration有望采用反应式编程的特征和优势。

总之,Spring 5代表着一次大受Spring开发人员欢迎的华丽转变,同时也为其他框架指出了一条发展之路。Spring 5的升级也为Spring Boot、Spring Cloud提供了非常丰富的经验,Spring不只是一个框架,已然成了一个编程生态。

我这样回答了Spring 5的新特性,面试官对我刮目相看的更多相关文章

  1. Spring Cloud Greenwich 新特性和F升级分享

    2019.01.23 期待已久的Spring Cloud Greenwich 发布了release版本,作为我们团队也第一时间把RC版本替换为release,以下为总结,希望对你使用Spring Cl ...

  2. 【Spring注解驱动开发】面试官:如何将Service注入到Servlet中?朋友又栽了!!

    写在前面 最近,一位读者出去面试前准备了很久,信心满满的去面试.没想到面试官的一个问题把他难住了.面试官的问题是这样的:如何使用Spring将Service注入到Servlet中呢?这位读者平时也是很 ...

  3. JDK8新特性面试

    java8:http://ifeve.com/java-8-features-tutorial/ 一.Lambda表达式和函数式接口 Lambda表达式(也叫做闭包) 它允许我们将一个函数当作方法的参 ...

  4. Spring 3.1新特性之三:Spring对声明式缓存的支持

    一.概述: Spring 3.1 引入了激动人心的基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如EHCache 或者 OSCache),而是一个对缓 ...

  5. 【Finchley】【新特性】Spring Cloud Finchley 新特性

    Finchley 正式版的发布貌似经历了相当长的时间,这次的重大发布主要带来了以下 4 项重大更新. 重大更新 1.新增 Spring Cloud Gateway 组件 Spring Cloud Ga ...

  6. Spring 3.1新特性之二:@Enable*注解的源码,spring源码分析之定时任务Scheduled注解

    分析SpringBoot的自动化配置原理的时候,可以观察下这些@Enable*注解的源码,可以发现所有的注解都有一个@Import注解.@Import注解是用来导入配置类的,这也就是说这些自动开启的实 ...

  7. Spring 3.1新特性之一:spring注解之@profile

    前言 由于在项目中使用Maven打包部署的时候,经常由于配置参数过多(比如Nginx服务器的信息.ZooKeeper的信息.数据库连接.Redis服务器地址等),导致实际现网的配置参数与测试服务器参数 ...

  8. Spring 3.1新特性之四:p命名空间设置注入(待补充)

    https://www.ibm.com/developerworks/cn/java/j-lo-jparelated/ http://www.ibm.com/developerworks/cn/jav ...

  9. Spring 3.1新特性之三:Spring支持Servlet 3.0(待补充)

    高效并发是JDK 1.6的一个重要主题,HotSpot虚拟机开发团队在这个版本上花费了大量的精力去实现各种锁优化技术,如适应性自旋(Adaptive Spinning).锁削除(Lock Elimin ...

随机推荐

  1. PHP后端代码生成微信小程序带参数的二维码保存成jpg图片上传到服务器getwxacodeunlimit

    老板最近有点飘了,他要在PC端的网站放一个微信小程序的二维码,并且扫描这个二维码以后要跳到小程序对应的房源详情页. 这是微信官方给出的文档,连接地址:https://developers.weixin ...

  2. C语言I作业09

    问题 回答 这个作业属于哪个课程 C语言程序设计II 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/SE2019-2/homework/10032 我在 ...

  3. centOS7 可以ping通主机不能访问外网

    前言: 突然打开自己前不久在虚拟机安装的centOS7系统,发现以前可以来联网突然不能访问外网,在网上看了很多方法,终于解决 问题描述: 连上网,但是ping 不同外网,如ping www.baodu ...

  4. 关于javascript中=的返回值

    今天看了一段代码,大概是这样的: function test(){ a=4; b=5; return b=a; } test();//返回? 返回值是多少呢?运行结果是4 这可以理解为将a的值赋给b以 ...

  5. JQuery之Ajax应用

    众所周知JQuery中的Ajax主要用于数据传输,其数据传输格式为JSON格式数据,比XML格式数据传输更快. ajax 是 Asynchronous JavaScript and XML的简写,aj ...

  6. 移动前端不得不了解的HTML5 head 头标签 —— link 标签

    目录 link 标签 rss订阅 不推荐的link标签 favicon 图标 link 标签 说到 link 标签,估计大家的第一反应和我一样,就是引入外部CSS样式文件的,不错,这是 link 标签 ...

  7. Java修炼——FileInputStream和FileOutputStream

    文件字节流FileInputStream是读文件内容 有一下五个方法 1) abstract int read( ); 2) int read( byte b[ ] ); 3) int read( b ...

  8. [TimLinux] JavaScript 给表单提前之前进行验证的方法

    1. onSubmit事件 这个事件是注册到form表单上的,不是注册在input type="submit"这个input按钮上面的. 2. 注册方式 HTML内部注册:< ...

  9. [TimLinux] MySQL 中的CASE/WHEN语法

    1. 介绍章节 MySQL 5.7-en.a4.pdf文档的第12章:Functions and Operators中的12.4Control Flow Functions介绍了流控制操作符:CASE ...

  10. C和C++从零开始系列(一)

    今天开始写下一系列C和C++从入门开始的文章. 简单说几句C和C++的关系.C语言早于C++. C语言 贝尔实验室的Ken Thompson发明了 UNIX,当时有个B语言的.后来D.M.Ritchi ...