对于Java开发者来说,2017年9月是个热闹的月份。不仅JavaSE9和JavaEE8相继发布,就连Spring框架也在这段时间发布了5.0正式版。新版Spring的一大特色是ReactiveWeb解决方案WebFlux。这是用来代替SpringWebMVC的吗?还是最终有可能摆脱基于servlet容器的依赖?基于Servlet容器的WebMVC作为Java开发人员,您对Spring框架并不陌生。起源于2002年RodJohnson的书《Expert One-on-One J2EE Design and Development》中的Interface21框架,2004年推出Spring1.0。从XML到3.0,支持JavaConfig设置;更进一步,2014年,除了Spring4.0之外,***还发布了SpringBoot,其亮点是使用了自动配置,使得基于Spring的快速开发成为可能。对于Web开发者来说,Spring中的WebMVC框架也随着Spring一起成长。但是因为它是基于Servlet容器的,所以早期被诟病难以测试(例如:controller包含ServletAPI)。不过,从实际操作Controller界面用XML设置,到后面用JavaConfig打上标签,WebMVC用起来越来越方便了。如果愿意,也可以采用循序渐进的方式,将基于ServletAPI的Web应用逐步重构为几乎没有ServletAPI,达到在程序代码层面屏蔽ServletAPI的效果。由于很多Java开发者的web开发经验都是从Servlet容器开始积累的,这时候基于ServletAPI的WebMVC框架就会占优势。因为,虽然使用WebMVC写程序,不能直接面对ServletAPI,但这也意味着你被Spring的约束更强烈,有时在设置或API上找不到相应的解决方案,有时又因为心智模型还挂在Servlet容器中,经验上很难摆脱。当想不通HttpSession和ServletContext对应的功能时,直接从HttpSession和ServletContext入手也是一种方式。在写程序的时候,即使不使用ServletAPI,WebMVC基于Servlet容器也是事实,因为底层还是要依赖Servlet容器的功能,比如SpringSecurity,它本质上是一个基于Servlet容器的Filter解决方案。然而,今天,Servlet被许多开发人员视为陈旧、过时技术的象征。或许也正因如此,在JavaEE8公布的那段时间,在某些场合提到Servlet4.0的时候,总会听到有人提出“WebFlux可以脱离Servlets”之类的建议。实现ReactiveStreams的ReactorWebFlux不依赖Servlet容器是事实。不过,在谈WebFlux之前,我们必须先了解一下Reactor项目,该项目由Spring的现任所有者Pivotal推出,实现了ReactiveStreams规范。支持响应式编程的实现。既然实现了ReactiveStreams规范,那么开发者肯定会想到RxJava/RxJava2,或者说Java9的FlowAPI。这也意味着开发者在使用WebFlux之前必须对ReactiveProgramming范式有所了解。开发者此时会有疑问,为什么Spring不直接基于RxJava2,而是创建一个专门的ReactiveStreams项目呢?就技术而言,Reactor是在Java8的基础上开发的,全面拥抱Java8之后的新API,比如Lambda相关的接口,新的日期时间API等。这意味着如果项目还是基于Java7或更早版本,无法使用Reactor。在API层面,RxJava2由于历史的发展,不得不保留一些容易混淆或容易混淆的类型或操作,而Reactor在这方面有明确的对应API来替代它。但是,它还提供与RxJava2(甚至FlowAPI)之间的转换。另一方面,Reactor更直观易用,比如最常介绍的Mono和Flux,实现了ReactiveStreams的Publisher接口,简化了信息发布,让开发者不用去处理Subscriber的细节以及很多场合下的订阅(当然,这些也是在Reactor中实现的)。在SpringWebFlux中,Mono和Flux也是主要的操作对象。如果想了解如何使用Mono和Flux,可以参考《ReactiveProgrammingUsingReactor》(https://goo.gl/vc2fGc)。另一个网络框架?Spring5在Reactor的基础上增加了WebFlux作为ReactiveWeb的解决方案。我们在很多介绍文件中都介绍了简单的示例,比如《使用Spring5的WebFlux开发响应式Web应用》(https://goo.gl/G5uotZ),可以看到使用了Flux和Mono来进行演示,代码如下该程序看起来像SpringMVC。这是因为WebFlux提供了基于Java的注解。WebMVC中使用的很多注解在WebFlux中也同样使用,方便熟悉WebMVC的开发者理解和上手WebFlux。然而,这不过是一个新的web框架吗?实际上,当然不是。WebFlux不依赖于WebMVC,它基于Reactor,它本质上是一种异步、非阻塞、响应式编程的思维模型。因此,如果你打算在Servlet容器上运行WebFlux,你必须支持Servlet3.1或以上版本,因为有非阻塞输入和输出支持,虽然WebFlux的API在某些地方确实提供了阻塞选项,如果你只是尝试基于WebMVC重写应用程序来应用WebFlux,并没有任何好处,但如何在WebFlux中实现相应的解决方案将是一个难题。比如这个时候,SpringSecurity显然就不能用了。毕竟是Spring基于Servlet的安全方案。开发人员必须找到一种方法来应用SpringSecurityReactive;而且,在存储方案中并没有直接使用SpringData,而是SpringDataReactive等。即使相关设置和API可以应用,要想获得WebFlux的好处,应用中的相关组件也必须彻底审查并重新设计为非阻塞并基于响应式编程。这可能是最困难和最麻烦的部分。除了熟悉WebMVC的开发者易于理解的基于Java注解的方式外,WebFlux还提供了基于函数式的设计和配置方式。事实上,在使用RxJava2/Reactor等ReactiveStreams时,我们必须熟悉函数式的思维方式,才能完全掌握。这在WebFlux中也不例外。能不能脱离Servlet容器?Servlet容器是旧时代的象征。如果能够屏蔽掉Servlet容器或者相关的API,很多开发者应该会很高兴。它可以减少抽象层并且不需要使用胖Servlet容器。当然,在使用WebFlux时,这将是一个额外的优势。但是,如果只是为了屏蔽Servlets,其实其他的技术选项早就存在了。基于Servlet的WebMVC一路发展。虽然目前在某些地方可以插入一些功能设计,但本质上没有变化的部分是,技术栈中隐含的仍然是一个基于同步的、阻塞式的、命令式的心智模型。如果在这样的栈中,开发者总是因为想要实现异步、非阻塞、响应式、函数式而感到不爽,WebFlux或许是一个可以考虑的解决方案,而不仅仅是作为脱离Servlet容器的一种方式,WebMVC的替代品。总体来说,WebFlux还是一项新技术,其可行性还需要时间来验证。如果你只是想用WebFlux来代替WebMVC,或者你的野心比较小,只是希望能够脱离Servlet容器。在采取行动之前,先全面了解一下,确认你或你的团队成员是否准备好接受WebFlux的心智模型,或者是否有相应的应用场景。
