最近有朋友拿到了一份offer,他很满意。在和他的交谈中,他了解到面试官问了他很多关于Spring的问题。其中,最让面试官满意的是他把关于Spring5的知识点回答的很好。Spring5于2017年9月发布,到现在已经快两年了。很多人可能不知道它有什么特点。最近正好看了一本书《Spring 5 核心原理与30个类手写实战》,觉得里面的内容还不错。经作者授权,摘录部分内容,介绍Spring5的新特性,文末还会送本书5册。Spring5于2017年9月全面发布,这是自2013年12月以来的第一个主要Spring版本。它提供了一些期待已久的改进,还包含基于反应式原则的全新编程范式。此版本是很长一段时间以来最激动人心的版本。Spring5与Java?8和JDK9兼容,集成了ReactiveStreams,为端点和Web应用程序开发提供了一种颠覆性的方法。当然,响应式编程不仅仅是这个版本的主题,它还是让许多程序员兴奋的主要特性。对可以针对负载波动进行无缝扩展的容灾和响应式服务的需求越来越大,而Spring5很好地满足了这一需求。下面来看看JavaSE8和JavaEE7API升级的基础知识,Spring5的新反应式编程模型,对HTTP/2的支持,以及Spring通过Kotlin对函数式编程的全面支持。它还简要介绍了测试和性能增强,并以对Spring核心和容器的一般修订作为结尾。升级到JavaSE8和JavaEE7之前Spring一直支持一些已弃用的Java版本,而Spring5已经摆脱了“旧包袱”。它的代码库已经过改进,可以充分利用Java8的特性,并且需要Java8作为最低JDK版本。Spring5在类路径(和模块路径)上与Java9完全兼容,并通过了JDK9测试套件。这对Java9粉丝来说是个好消息。在API层面,Spring5兼容JavaEE8技术,满足Servlet4.0、BeanValidation2.0和新的JSONBindingAPI的要求。JavaEEAPI的最低要求是V7,它引入了Servlet、JPA和BeanValidationAPI的次要版本。反应式编程模型Spring5最令人兴奋的新特性是它的反应式编程模型。Spring5建立在反应式基础上,是完全异步和非阻塞的。新的事件循环执行模型仅通过少量线程垂直扩展。Spring5采用ReactiveStreams提供一种在反应组件中传播负压的机制。负压是确保消费者不会被来自多个生产者的数据淹没的概念。SpringWebFlux是Spring5的反应式核心,它为开发者提供了两种专为SpringWeb编程设计的编程模型:基于注解的模型和FunctionalWebFramework(WebFlux.fn)。基于注解的模型是SpringWebMVC的现代替代方案,它建立在反应性基础上,而FunctionalWebFramework是基于@Controller注解的编程模型的替代方案。这些模型都通过相同的反应规则运行,这些规则使非阻塞HTTP适应反应流API。使用注解编程WebMVC程序员应该熟悉Spring5的基于注解的编程模型,它采用WebMVC的@Controller编程模型来使用相同的注解。在下面的代码中,BookController类提供了两种方法,分别响应对图书列表的HTTP请求和对具有给定id的图书的HTTP请求。注意诸如Mono和Flux之类的对象。这些对象是响应式类型,实现了ReactiveStreams规范中的Publisher接口,它们的职责是处理数据流。Mono对象处理只有1个元素的流,而Flux代表N个元素的流。@RestControllerpublicclassBookController{//反应式控制器@GetMapping("/book")Fluxlist(){returnthis.repository.findAll();}@GetMapping("/book/{id}")MonofindById(@PathVariableStringid){returnthis.repository.findOne(id);}}以上是SpringWeb编程的注解。下面我们使用一个函数式Web框架来解决同样的问题。函数式编程Spring5的函数式方法将请求委托给采用服务器请求实例并返回反应类型的处理函数。我们来看一段代码,创建一个BookHandler类,其中listBooks()和getBook()方法相当于Controller中的函数。publicclassBookHandler{publicMonolistBooks(ServerRequestrequest){returnServerResponse.ok().contentType(APPLICATION_JSON).body(repository.allPeople(),Book.class);}publicMonogetBook(ServerRequestrequest){tory.repositrequest(.pathVariable("id")).then(book->ServerResponse.ok().contentType(APPLICATION_JSON).body(fromObject(book))).otherwiseIfEmpty(ServerResponse.notFound().build());}}通过路由函数来匹配HTTP请求参数和媒体类型,并将客户端请求路由到处理函数。以下代码显示书籍资源端点URI将调用委托给适当的处理函数:BookHandlerhandler=newBookHandler();RouterFunctionpersonRoute=route(GET("/books/{id}").and(accept(APPLICATION_JSON)),handler::getBook).andRoute(GET("/books").and(accept(APPLICATION_JSON)),handler::listBooks);这些示例背后的数据存储也支持完整的响应式体验,这是通过SpringData对响应式Couchbase、ReactiveMongoDB和Cassandra的支持实现的。使用REST端点进行响应式编程新的编程模型脱离了传统的SpringWebMVC模型,并引入了一些不错的新功能。例如,WebFlux模块提供了一个完全非阻塞的、响应式的RestTemplate替代方案,称为WebClient。让我们创建一个WebClient并调用书籍端点以请求给定ID为1234的书籍。//调用REST端点Monobook=WebClient.create("http://localhost:8080").get().url("/books/{id}",1234)通过WebClient.accept(APPLICATION_JSON).exchange(request).then(response->response.bodyToMono(Book.class));支持HTTP/2HTTP/2可提高传输性能、减少延迟并提高应用程序吞吐量,从而提供丰富的Web体验。Spring5提供了专门的HTTP/2功能支持,还支持人们期望在JDK9中使用的新HTTP客户端。尽管HTTP/2的服务器推送功能已经通过JettyServlet引擎的ServerPushFilter类向Spring开发人员公开了很长时间,但Web优化人员必须确保发现HTTP/2性能增强在Spring5中提供了开箱即用的功能。会为之欢呼。Spring5.1提供了Servlet4.0,HTTP/2的新特性将由Tomcat9.0、Jetty9.3和Undertow1.4原生提供。Kotlin和SpringWebFluxKotlin是JetBrains的一种支持函数式编程的面向对象语言。它的主要优势之一是与Java的高度互操作性。Spring5通过引入对Kotlin的专门支持来全面利用这一优势。它的函数式编程风格与SpringWebFlux模块完美匹配,其新的路由DSL利用具有干净和惯用代码的函数式Web框架。端点路由可以简单的表达为如下代码://Kotlin用于定义端点的路由DSL@BeanfunapiRouter()=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)}}}使用Kotlin1.1.4+时,还添加了对Kotlin不可变类的支持(通过具有默认值的可选参数),以及对完全空感知API的支持.使用Lambda表达式注册Bean作为传统XML和JavaConfig的替代方案,现在可以使用Lambda表达式注册SpringBeans,从而允许将bean实际上注册为提供者。以下代码使用Lambda表达式注册BookBean:GenericApplicationContextcontext=newGenericApplicationContext();context.registerBean(Book.class,()->newBook(context.getBean(Author.class)));SpringWebMVC支持最新的API的全新WebFlux模块提供了许多令人兴奋的新功能,但Spring5也迎合了愿意继续使用SpringMVC的开发人员的需求。“模型-视图-控制器”框架已在Spring5中进行了更新,以与WebFlux以及最新版本的Jackson2.9和Protobuf3.0兼容,甚至包括对新的JavaEE8JSON-BindingAPI的支持。除了HTTP/2特性的底层服务器实现,SpringWebMVC还通过MVC控制器方法的参数支持Servlet4.0的PushBuilder。最后,WebMVC完全支持Reactor3.1的Flux和Mono对象,以及RxJava1.3和RxJava2.1,它们被视为MVC控制器方法的返回值。这种支持的最终目标是支持SpringData中新的反应式WebClient和反应式存储库。使用JUnit5执行条件和并发测试1.JUnit和Spring5Spring5完全接受功能范例并支持JUnit5及其新的功能测试风格。还提供了对JUnit4的向后兼容性,以确保遗留代码不被破坏。Spring5的测试套件在许多方面得到了增强,但最引人注目的是它对JUnit5的支持。现在可以在单元测试中利用Java8中可用的函数式编程功能。以下代码演示了这种支持:@TestvoidgivenStreamOfInts_SumShouldBeMoreThanFive(){assertTrue(Stream.of(20,40,50).stream().mapToInt(i->i).sum()>110,()->"Totalshouldbemorethan100");}2.迁移到JUnit5如果您对升级到JUnit5犹豫不决,StevePerry的两部分深入教程将说服您尝试一下。Spring5继承了JUnit5的灵活性,可以在SpringTestContextFramework中实现多个扩展API。例如,开发人员可以使用JUnit5的条件测试执行注释@EnabledIf和@DisabledIf来自动评估SpEL(Spring表达式语言)表达式并适当地启用或禁用测试。通过这些注解,Spring5支持了以前难以实现的复杂条件测试场景。SpringTextContextFramework现在能够并发执行测试。3.使用SpringWebFlux执行集成测试SpringTest现在包含一个支持针对SpringWebFlux服务器端点的集成测试的WebTestClient。WebTestClient使用模拟请求和响应来避免耗尽服务器资源,并且可以直接绑定到WebFlux服务器的基础结构。WebTestClient可以绑定到真实服务器,或者使用控制器或函数。在以下代码中,WebTestClient绑定到本地主机:WebTestClienttestClient=WebTestClient.bindToServer().baseUrl("http://localhost:8080").build();以下代码将WebTestClient绑定到RouterFunction:RouterFunctionbookRouter=RouterFunctions.route(RequestPredicates.GET("/books"),request->ServerResponse.ok().build());WebTestClient.bindToRouterFunction(bookRouter).build().get().uri("/books").exchange().expectStatus().isOk().expectBody().isEmpty();包清理和弃用Spring5结束了对一些过时API的支持。Hibernate3和Hibernate4遭受了这种命运,它们被弃用,取而代之的是Hibernate5。此外,对Portlet、Velocity、JasperReports、XMLBeans、JDO和Guava的支持已经结束。包级别的清理工作继续进行。Spring5不再支持beans.factory.access、jdbc.support.nativejdbc、mock.staticmock(来自spring-aspects模块)或web.view.tiles2M。Tiles3现在是Spring的最低要求。Spring核心和容器Spring5的一般更新改进了扫描和识别组件的方式,从而提高了大型项目的性能。目前,扫描是在编译时执行的,组件坐标被添加到META-INF/spring.components文件中的索引文件中。该索引是通过为项目定义的特定于平台的应用程序构建任务生成的。标有来自javax包的注解的组件被添加到索引中,任何用@Index注解的类或接口也是如此。Spring传统的类路径扫描方式并没有被移除,而是被保留下来作为后备。大型代码库有许多明显的性能优势,托管许多Spring项目的服务器也可以缩短启动时间。Spring5还添加了对@Nullable的支持,可用于指示可选注入点。消费者现在必须准备好接受空值。此外,此注释可用于标记可为null的参数、字段和返回值。@Nullable主要用在IntelliJIDEA等IDE中,但也可以用在Eclipse和FindBugs中,这样可以更方便的在编译时处理null值,而不用在运行时发送NullPointerExceptions。SpringLogging还提高了性能,并附带了一个开箱即用的CommonsLogging桥。现在通过资源抽象支持防御性编程,为getFile访问提供isFile指示符。我如何看待Spring5Spring5的首要特性是新的反应式编程模型,它代表了对提供无缝可扩展的、基于Spring的反应式服务的主要承诺。随着Spring5的采用,响应式编程有望成为使用Java语言进行Web和企业应用程序开发的未来。Spring的未来版本将继续体现这一承诺,因为SpringSecurity、SpringData和SpringIntegration有望采用反应式编程的特性和优势。总而言之,Spring5代表了Spring开发人员可喜的变化,同时也为其他框架的发展指明了方向。Spring5的升级也为SpringBoot和SpringCloud提供了丰富的体验。Spring不仅仅是一个框架,而是已经成为一个编程生态系统。