就像在昨天Juergen发布的博客的一样,Spring 5.0框架第二个里程碑版本中介绍了一个新的函数式web框架。在这篇文章中,我将更详细的介绍这个框架。 示例我们选用示例程序作为开始。下面是一个响应资源库用于暴露Person对象。这个响应资源库与传统的无响应资源库类似,除了Flux<Person>对应传统的 List<Person>,Mono<Person>对应传统的 Person对象。Mono<Void>作为完成标识:用于指示保存工作完成.更多Reactor 类型信息请查阅 Dave发布的博客
这里我们介绍如何使用新的函数式web框架暴露资源库:
这里我们介绍如何运行它,下面是Reactor Netty的示例:
最后要做的是,进行一次尝试请求:
上面的介绍覆盖了很多内容,下面让我们深入挖掘下! |
核心组件
|
1
2
|
HandlerFunction<String> helloWorld = request -> Response.ok().body(fromObject( "Hello World" )); |
如上,构建于Reactor之上的处理方法是完全的响应式的(reactive),它们可以接受Flux、Mono或者其他相应流(Reactive Streams)的发布者作为返回类型的参数。
需要注意的是处理方法本身是没有副作用的,因为它将response作为返回值,而不是作为参数(对比Servlet.service(ServletRequest,ServletResponse),其实质是BiConsumer<ServletRequest,ServletResponse>)。无副作用的方法有很多好处:更有利于测试、构建和优化。
路由功能入站请求是由RouterFunction<T>,(即Function<Request, Optional<HandlerFunction<T>>)路由到HandlerFunction中去的。当满足条件匹配时,路由方法会执行处理方法,否则会返回一个空结果。路由方法与@RequestMapping注解的作用相似。但是,还有一个显著的区别:用注解时路由会被限制到注解的value所能表达的范围,处理这些方法的覆盖是困难的;当用路由方法的时候,代码就在那里,可以轻松的覆盖或替换。 如下是一个路由方法的例子,包含了一个行内的处理方法。这里看起来有一点冗余,不必担心,因为后面我们将会将它变得精简。
一般不用写完整的路由方法,而是静态引入RouterFunctions.route(),这样就可以用请求判断式(RequestPredicate) (即 Predicate<Request>)和处理方法(HandlerFunction)创建路由方法了。如果判断式判断成功则返回处理方法,否则返回空结果。如下是用route方法方式重写上面的例子:
静态引入RequestPredicates.*后就可以使用那些常用的判断式了,如匹配路径、HTTP方法、content-type等。这样上面的例子将会变得更精简:
|
组合功能
|
1
2
3
4
5
|
RouterFunction<?> route = route(path( "/hello-world" ), request -> Response.ok().body(fromObject( "Hello World" ))) .and(route(path( "/the-answer" ), request -> Response.ok().body(fromObject( "42" )))); |
上面的例子如果路径匹配/hello-world会返回“Hello World”,如果匹配/the-answer则返回“42”。如果都不匹配则返回一个空的Optional对象。注意,组合的路由是按顺序执行的,所以应该将更通用的方法放到更明确的方法的前面。
请求判断式也是可以组合的,通过调研and或者or方法。正如预期的一样:and表示给定的两个判断式同时满足则组合判断式满足,or则表示任意判断式满足。如下:
1
2
3
4
5
|
RouterFunction<?> route = route(method(HttpMethod.GET).and(path( "/hello-world" )), request -> Response.ok().body(fromObject( "Hello World" ))) .and(route(method(HttpMethod.GET).and(path( "/the-answer" )), request -> Response.ok().body(fromObject( "42" )))); |
实际上,RequestPredicates中的大部分判断式都是组合的!比如RequestPredicates.GET(String)是RequestPredicates.method(HttpMethod)和RequestPredicates.path(String)的组合。所以上面的例子可以重写为:
1
2
3
4
5
|
RouterFunction<?> route = route(GET( "/hello-world" ), request -> Response.ok().body(fromObject( "Hello World" ))) .and(route(GET( "/the-answer" ), request -> Response.ok().body(fromObject( 42 )))); |
方法引用
此外,目前为止我们的处理方法都是行内的lambda表达式。尽管这样很适合于实例和简短的例子,但是当结合请求路由和请求处理两个关注点时,可能就有变“混乱”的趋势了。所以我们将尝试将他们简化。首先,创建一个包含处理逻辑的类:
1
2
3
4
5
6
7
|
class DemoHandler { public Response<String> helloWorld(Request request) { return Response.ok().body(fromObject( "Hello World" )); } public Response<String> theAnswer(Request request) { return Response.ok().body(fromObject( "42" )); }} |
注意,这两个方法的签名都是和处理方法兼容的。这样就可以方法引用了:
1
2
3
4
|
DemoHandler handler = new DemoHandler(); // or obtain via DI RouterFunction<?> route = route(GET( "/hello-world" ), handler::helloWorld) .and(route(GET( "/the-answer" ), handler::theAnswer)); |
结论 至此便结束了对 Spring 新函数式 web 框架的介绍。让我简单小结一下:
|
本文转自:开源中国社区 [http://www.oschina.net]
本文标题:Spring 5 新功能:函数式 Web 框架
本文地址:https://www.oschina.net/translate/new-in-spring-5-functional-web-framework
参与翻译:debugging, 达尔文, 混元归一, leoxu, xufuji456
英文原文:New in Spring 5: Functional Web Framework