Spring 5 新特性总结
一、 升级到Java SE 8 和 Java EE 7
- 将Java8作为最低的JDK版本。
- Spring5在类路径(和模块路径)中完全兼容Java9,而且它通过了JDK9测试套件的测试。
- 在API级别上,Spring5兼容Java EE8技术,满足对Servlet4.0、Bean Validation2.0和全新的JSON Binding API的需求。对Java EE API的最低要求为V7,该版本引入了针对Servlet、JPA和Bean Validation API的次要版本。
二、 反应式编程模型
- Spring5最令人兴奋的新特性是它的反应式编程模型,它是完全异步和非阻塞的。只需少量的线程,新的事件循环执行模型就可以垂直扩展。
- Spring5采用反应式流来提供在反应式组件中传播负压的机制。负压是一个确保来自多个生产者的数据不会让使用者不堪重负的概念。
- Spring WebFlux是Spring 5的反应式核心,它为开发人员提供了两种为Spring Web编程而设计的编程模型:基于注解的模型和Functional Web Framework(WebFlux.fn)
- 基于注解的模型是Spring Web MVC的现代替代方案,该模型基于反应式基础而构建,而Functional Web Framework是基于@Controller注解的编程模型的替代方案。这些模型都通过同一种反应式规则来运行,后者调整非阻塞HTTP来适应反应式流API。
三、 使用注解进行编程
Spring 5调整了Web MVC的@Controller编程模型,采用了相同的注解。请注意Mono和Flux等对象是实现反应式流规范中的Publisher接口的反应式类型,它们的职责是处理数据流。
@RestController // 反应式控制器
public class SimpleController {
@GetMapping("/list")
public Flux<PatentInformation> list(){
return null;
}
}
四、 函数式编程
Spring 5的函数式方法将请求委托给处理函数,这些函数接收一个服务器请求实例并返回一种反应式类型。
public class BookHandler {
public Mono<ServerResponse> list(ServerRequest request){
return ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(repository.allPeople(),Book.class);
}
public Mono<ServerResponse> getBook(ServerRequest request){
return repository.getBook(request.pathVariable("id"))
.then(book->ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(fromObject(book)))
.otherwiseIfEmpty(ServerResponse.notFound().build());
}
}
通过路由函数来匹配HTTP请求参数与媒体类型,将客户端请求路由到处理函数。下面的代码展示了图书资源端点URI将调用委托给合适的处理函数:
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
BookHandler handler = new BookHandler();
RouterFunction<ServerResponse> personRoute =
route(
GET("/books/{id}")
.and(accept(MediaType.APPLICATION_JSON)),handler::getBook)
.andRoute(GET("/books")
.and(accept(MediaType.APPLICATION_JSON)),handler::list);
这些示例背后的数据存储也支持完整的反应式体验,该体验是通过Spring Data对反应式Couchbase、Reactive MongoDB和Cassandra的支持来实现的。
五、 使用REST端点执行反应式编程
WebFlux模块为RestTemplate提供了一种完全非阻塞、反应式的替代方案,名为WebClient:
Mono<Book> book = WebClient.create("http://localhost:8080")
.get()
.uri("/books/{id}",123)
.accept(MediaType.APPLICATION_JSON)
.exchange(request)
.then(response->response.bodyToMono(Book.class));
六、 支持HTTP/2
HTTP/2提高了传输性能,减少了延迟,并提高了应用程序的吞吐量。尽管HTTP/2的服务器推送功能已通过Jetty Servlet引擎的ServerPushFilter类向Spring开发人员公开。
Spring 5.1提供Servlet4.0,Http/2新特性将由Tomcat9.0、Jetty9.3和Undertow1.4原生提供。
七、 Kotlin 和 Spring WebFlux
八、 使用Lambda表达式注册Bean
作为传统XML和JavaConfig的替代方案,现在可以使用Lambda表达式注册Spring Bean。
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean(Book.class,()->new Book(context.getBean(Author.class)));
九、 使用Junit5执行条件和并发测试
1.1. Junit5的支持
@Test
void sumTest(){
assertTrue(Stream.of(20,40,50).mapToInt(i->i).sum()>110,()->"Total then 100");
}
1.2. 迁移到Junit5
Junit5条件测试执行注解@EnabledIf 和@DisabledIf来自动计算一个SpEL(Spring Expression Language)表达式,并适当启用或禁用测试。
1.3. 使用Spring WebFlux执行集成测试
WebTestClient可绑定到真实的服务器,或者使用控制器或函数。
在下面的代码中,WebTestClient被绑定到localhost:
WebTestClient testClient = WebTestClient.bindToServer()
.baseUrl("http://localhost:8080")
.build();
下面的代码将WebTestClient绑定到RouterFunction:
RouterFunction bookRouter = RouterFunctions.route(
RequestPredicates.GET("/books"),
serverRequest -> ServerResponse.ok().build()
);
WebTestClient.bindToRouterFunction(bookRouter)
.build()
.get()
.uri("/books")
.exchange()
.expectStatus()
.isOk()
.expectBody()
.isEmpty();