“Spring 之父 ”Rod.Johnson 曾经写过一本在 Java 界引起轰动的书:《 Expert One-on-One J2EE Development Without EJB 》。这本书阐述了 EJB 作为 J2EE 核心技术所带来的意义与价值,但作者用了更大篇幅介绍 EJB 的一些缺陷与不足,并提出了 Without EJB 的解决方案。正是由于 “J2EE Without EJB” 这个激动人心的口号及这本书奠定的基础,导致了 Spring Framework 这个经典轻量级框架的诞生。
时至今日, Ajax 已经成为一个红得发紫的技术。但是今天,我想说一句: JavaEE without Ajax 。
Ajax 的“原罪”
Ajax 为什么这样红?有人说,是因为起了个好听易记的名字(比如荷兰著名的 Ajax 球队,即阿贾克斯);也有人说,是因为 Google 全新的 Ajax 应用产品给人们带来的超酷体验(比如伟大的 Google Maps 、 GMail 等)。确实如此, Ajax 能够如此流行的最主要原因就是它带来了更好的用户体验,改变了人们对传统 Web 应用的不佳印象。
然而,即使 Ajax 的狂热 Fans 也不得不承认的是,从技术层面上来说, Ajax 并没有带来什么新鲜的东西。它本质上是一种新瓶装旧酒的技术,好处是通过 Java Script 与 DHTML 提供了一种异步编程模型,从而使 Web 应用给客户带来了更好的人机体验。正如我在去年引起大家争论的拙文《 Ajax ,只是一种过渡技术》中表述的: Ajax 解决问题的层面较低。或者说,它解决问题的方法与手段,很难形成一种可高度抽象的框架级解决方案。并且,正是因为 Ajax 基于 Java Script ,因此不可避免地带来了 Java Script 的诸多缺点,譬如:
跨浏览器是一场噩梦
对搜索引擎的支持不好
干掉了 Back 、 History 等按钮(尽管我并不认为 Back 、 History 是什么好东西)
开发与维护成本过高
要 Java, 不要 Java Script
We Love Java, Not Java Script 。套用毛泽东的惯用句式就是: “ 要 Java, 不要 Java Script” 。相信很多读者看完这个标题也许会不以为然,但这句话却代表了许多 J2EE 开发人员的心声。
众多 Java 工程师都对 Java 有一种近乎偏执的喜爱,他们热爱 Java 的简洁与优雅。但一旦让他们去进行 Java Script 的开发,却往往会不知所措:过度灵活的语法,无法通过编译器进行语法校验,缺乏良好的调试工具等等这些,都会让人们对 Java Script 畏手畏脚,更遑论 Ajax 的开发。
一句话, Java 社区需要 Ajax ,需要它来提升基于 JavaEE 的 Web 应用的人机体验;但是,人们并不喜欢 Ajax 目前的开发模式。无疑,我们需要一种新的解决方案。
谁来拯救 JavaEE 的 Ajax ?
我给出的答案是 JSF 。目前,关于 JSF 的一种流行说法是“悲剧人生: Sun 让 JSF 光着身子降临到 Java Web 世界”。然而,我的看法却是:作为一种革命性的服务器端组件技术, JSF 犹如早晨八九点钟的太阳,前途不可限量。
让事实说话,我们先来看看 JSF 请求 / 响应过程的标准生命周期:
图1 :JSF 的生命周期
通过上图可以观察到,任何一个 JSF“Faces Request” 请求,经过 Restore View 、 Apply Request Values 、 Process Validations 、 Update Models 、 Invoke Application 等阶段以后,产生了一个 “Render Response” 返回给客户端。那么,常规 JSF 引擎是如何实现上述过程的呢?
图2 :常规 JSF 引擎的请求与响应过程
回顾一下常规 JSF 引擎针对请求与响应的过程:首先,客户端请求某个资源,产生一个 Faces Request ;服务器端接收到此请求以后,经过一系列后台处理,产生一个 Faces Response 。我们注意到:响应的 Content-Type 是 text/html ,而产生的内容主体是一段 HTML 文本;浏览器在接收到 HTML 文本以后,进行整个页面的渲染与刷新。
无需写 Ajax 代码的 Ajax Enabled 应用
我用自己开发的 JSF 引擎,这样处理上述过程(详见参考资料 www.OperaMasks.org ),如下图所示:
图 3 : OperaMasks JSF 实现的请求与响应过程
首先可以观察到, Faces Request 的发出是基于 “x-requested-by: XML Http Request” ,也就是说,这是一个 Ajax 请求,而该请求在到达服务器端以后,服务器端所产生的 Faces Response 同常规 Faces Response 相比也发生了变化: Content-Type 不再是 text/html ,变成了 text/javascript ;并且,响应的主体也不再是 html 文本,而是一堆 script 脚本。浏览器在接收到响应以后,再也不需要进行整个页面的渲染与刷新,而只仅仅需要执行这段脚本内容,将页面的控件进行更新即可。
显而易见,通过上述 JSF 技术,我们获得了:
基于 Ajax 的请求、应答、及页面控件的更新
数据传输量明显减少
避免整个页面的刷新,更好的用户体验
系统保持敏捷、高效
换言之:任何标准 JSF 应用,只需将其在 OperaMasks JSF 引擎上运行,就可以达到这样的效果。我们并没有写任何一行 Ajax 的代码,但是,我们的应用却是自然而然的 Ajax Enabled 的应用。大道至简,大象无形。
奥妙所在: JSF 的 Render 机制
为什么可以这样?
JSF 组件只是特定状态和行为的载体,而组件以什么形式去和用户交互,是完全可定制的、独立于该特定的表现语言,可以是 HTML 、 WML 或者其他形式;具体是什么,可以通过指定 JSF 组件的 Render Kit 来实现,而每一种 Render Kit ,对应于组件作者写的同一风格和形式的一系列 Render 。
比如,如果想在网页中实现图表功能( Chart) , MSIE 有 VML , Gecko 和 Opera 有 SVG ;而在服务器端只需要简单地判断一下浏览器类型,就可以选择一个 Render Kit ,生成不同的客户端表现来完成相同功能?D?D这是用常规 JSP 技术很难完成的任务。
通俗的说, JSF 组件可以翻译成任何你想要的形式。 So , JSF 框架比现有其它开源框架具有更强的生命力。上文所述的 OperaMasks JSF ,其容器级别 Ajax 实现,正是灵活应用 Render Kit 的具体案例。
从容器级别对 Ajax 予以支持的 JSF 引擎
我们提出的 JSF 是直接由 JSF 容器来处理 Ajax 请求的,它会根据请求类型来判断这是一个正常 HTTP 请求还是一个 Ajax 请求:如果是常规 HTTP 请求就运行 JSP 页面,生成页面文档(特定的,对于 Ajax Render kit ,要加入一些 Ajax 基础 JavaScript 代码);如果是 Ajax 请求,服务器对请求参数正常解码,并执行 JSF 中除页面输出阶段以外的所有其他阶段,生成一个 JSF 组件树。
一直到这一步为止,处理方式与对普通 HTTP 请求的处理完全一致,唯一不同的是:在随后 Render Response 阶段,容器除了调用组件作者写的 Ajax 功能 Renderer 以外,更重要的是在生成响应页面时,会过滤掉一切不会变化的静态内容?D?D也就是说,静态内容不会生成到响应页面中去,而对每一个动态内容则会生成一个相应 JavaScript 代码(可以更进一步优化为只有变化了的动态内容才处理)。这样,传给客户的 Ajax 应答实际上是由这样一些 JavaScript 语句构成。在 Ajax 响应返回到客户端时,就可以自动由 Ajax 回调函数执行这些 JavaScript 语句,完成对页面即时的、局部的更改,而不需要刷新整个页面。依赖 JSF 组件的具体功能,甚至可以改变页面的外观。而整个 Ajax 机制由 JSF 引擎提供,对用户完全透明。
实际上,在 JSF 规范中 JSF 页面输出阶段所采用的 Render Kit 是可替换的,默认的 HTML_BASIC Render Kit 输出的是标准 HTML 语法,不包含任何 Java Script 代码。我们提出的 JSF 引擎实现了一个 Ajax Render Kit ,可以在 HTML 文档中嵌入 Java Script 代码来实现 Ajax 特性,而替换 Render Kit 只需要修改配置文件即可。
简单地说,这种 JSF 引擎为每个标准组件都实现了相应的 Ajax Render , 比如对 UICommand 组件,其 Ajax Render 会在 onclick 事件中加入 JavaScript 的 Ajax 提交代码,向服务器提交 Ajax 请求。通过这种方式,任何一个包含标准 JSF 组件的 Web 应用,都可以通过只更改 Render Kit 配置为 Ajax 来实现 Web 应用 Ajax 化。而对于第三方的组件,可能本身并不支持 Ajax ,但使用一个名为
例如, Apache myfaces 的 Tomahawk 项目提供了一个 Tree 组件,这个组件本身并不支持 Ajax ,每当按下一个 Tree 结点都将重新刷新整个页面。使用
综上, JavaEE 需要 Ajax ,但并不需要传统的 Ajax 开发模式。通过我们提出的 OperaMasks JSF 技术,我们不再需要知道什么是 Ajax ,而我们的应用却是自然而然的 Ajax Enabled 应用。
因此,我们认为: JavaEE Without Ajax !