最近终于抽空阅读了JSR314与相关的API代码,把一些心得整理一下。
JSF 2.0阅读笔记:视图状态
什么是视图状态
在JSF中,一个页面,或者叫视图(View),在服务器端是通过一棵组件树来描述的。组件树中的每一个节点,对应着视图上的每一个组件,是组件在服务器端的内部表述模型,称为组件类实例。JSF请求处理生命周期中的所有行为,包括校验、转换、事件分发、渲染等等,都是围绕组件树进行的。任何时候,只要把组件树完整地建立起来,我们就拥有了它所表述的视图在请求处理生命周期中所需要的全部信息。这些信息,就称为视图状态信息。通常来说,视图状态信息包括了组件树的结构信息,组件中每一个组件的属性值,以及所有附加到这些组件上的其他对象(例如转换器和校验器等等)。而我们编写页面(xhtml或jsp)的行为,事实上是在定义组件树的初始状态。在JSF1.2规范中,官方只规定了一种编写页面的方式,jsp。在JSF2.0中,对定义页面初始状态的方式进行了抽象,支持多种页面定义方式,每一种方式称为一种视图声明语言(ViewDeclarationLanguage,或称VDL)。
在对页面的首次请求中,JSF引擎根据VDL的描述建立起初始状态的组件树。在后续的处理与postback处理中,应用系统会对视图状态进行修改。例如修改组件属性值,动态增删组件等等。由于http协议是无状态的,每次请求完毕后与这次请求相关的状态都会丢失。JSF引擎就承担起在请求处理生命周期的起始阶段把上一次请求的组件树恢复重建起来的职责。显然,实现这一目的最直接的做法是把整棵组件树保存在session中。但是,出于性能与服务器资源占用的综合考虑,JSF的实现框架通常会把恢复组件树的必要信息进行抽取和编码,以某种形式保存在session中或传递到客户端。在JSF规范中,就把这些信息称为视图状态。请注意“视图状态”这个术语的多重含义,在请求处理的语境中,它指组件树的当前状态。在恢复视图的语境中,它指“以某种形式传递到下一次请求,JSF引擎能根据它来重建组件树的必要信息”。至于这些“必要信息”保存的形式和传递的方式,根据具体实现不同而不同,可以是保存在session中组件树,也可以是经过序列化和BASE64编码的一串字符串。为了避免混淆,在下文中“视图状态”统一采用后一种含义。对于前一种含义,采用“组件树当前状态”来表述。
JSF规范和API把生产视图状态的过程划分为采集与编码两个阶段。采集的逻辑通过继承javax.faces.application.StateManager抽象类来实现,负责遍历组件树,把组件树结构(包括组件对象的类型信息,和组件对象之间的层次关系)、每个组件的状态信息和附加对象信息抽取出来,构造出一个可序列化的对象数组。编码阶段(针对把视图状态传递到客户端的情况),通过继承javax.faces.render.ResponseStateManager抽象类来实现,负责把上述的对象数组转换为某种可在网络上传输的(BASE64编码),安全的(加密)编码形式,并向响应流中输出。同理,在根据视图状态恢复组件树的过程中,也存在解码和恢复两个阶段,同样由上述两个抽象类的实现类来负责。当然,其中的实现细节都是JSF框架的实现者才需要关心的事,组件开发人员和应用开发人员都无需关心。
JSF 2.0之前的视图状态
在JSF 1.2或更早版本中,视图状态一直是一个尾大不掉的难题。
首先,组件类上存在大量的强类型的属性对象域,使得单个组件的视图状态尺寸虚高。比如说,组件有一个布尔型的属性叫immediate,那么组件开发者就会在这个组件类中加入一个private boolean immediate对象域。同时,由于要跟踪这个属性是否被显式地设置过,还要加入一个private boolean isImmediateSet对象域来记录。这样一来,即使在某个页面中我可能从来都没使用过这个属性,但这些对象域的值最终都会被加入到视图状态中去。可想而知,对于一个复杂的组件体系模型,单个组件上的属性数目很可能达到上百个,而事实上每次使用的只不过是其中三五个,将会使整个视图状态尺寸无谓地增大。需要注意的是,JSF规范中并没有规定要使用强类型对象域的方式来保存组件属性,但JSF1.2的官方API中采用了这种做法,导致组件开发者不得不效仿。
其次,组件开发者必须为每个组件类实现saveState与restoreState方法,来采集与恢复强类型对象域的状态。组件类上存在的大量强类型对象域,有的甚至没有作为JavaBean属性对外公开,是无法统一采集与恢复的。因此JSF规范为组件类准备了saveState与restoreState接口方法,组件开发者必须在每个组件类上覆盖这两个方法,依次采集与恢复各个需要保存状态的对象域。这为组件开发者带来了大量琐碎的重复工作。一些JSF实现采用了自动生成代码的方法来避开这个问题,但在开发组件的过程中需要人手去触发代码生成过程,不免令人不爽。
第三,视图状态尺寸极易失控,使应用开发者陷入两难处境。由于上述第一点原因,结构稍为复杂一点的页面往往会产生尺寸巨大的视图状态信息。更令人崩溃的是,JSF规范针对这种状况给出了一种火上浇油,掩耳盗铃式的“解决方案”:您可以选择把视图状态保存在服务器端,用内存换带宽;也可以选择把它传递到客户端,在下一次请求再提交上来,用带宽换内存。这下好了,应用程序员都变成了揭不开锅的小媳妇,小心翼翼地算着手上有几角几分,到底要带宽呢,还是要内存。要带宽,就意味着服务器资源吃紧,强并发用户数降低。要内存,就意味着明确表示56k modem与3G不得入内,也意味着需要尽量减少ajax提交频率。手心是肉,手背也是肉,你要割哪面?我曾尝试过加入gzip压缩方案来减少视图状态尺寸,但发现效果并不理想。虽然确实能把视图状态尺寸缩小到60%左右,但又把CPU扯进来了,无非是把两难选择变成了三难选择。治标不如治本,归根结底,从本质上减少视图状态尺寸才是正路。
第四,视图状态必须存在。事实上,并不是所有页面都需要更改视图状态,那么对于那些一直保持初始状态的视图,是否可以不保存视图状态,而改为在每次请求处理从原始页面重新构建组件树呢?答案是不行!JSF1.2规范只支持JSP这一种页面语言,而JSP本身是无比开放的,应用开发者倾向于在JSP中直接嵌入业务脚本,并且预期这些脚本只会在首次请求时才运行。在每次postback(特别是ajax postback)中都执行这些脚本显然不是应用开发者想要的。而JSF作为一个开发框架,与其禁止程序员在JSP中嵌入业务逻辑,造成概念上的混乱,还不如接受性能“稍慢”的现状。Facelets框架的出现改变了这种状况,为基于初始视图状态的“优化视图状态”提供了理论上的可能。Facelets页面只关心组件树的初始状态描述,无法嵌入业务逻辑(时髦的说法是没有side effect)。JSF的实现者可以在任何有需要的时候重新解析页面,获取到一份初始视图状态。
(待续)
分享到:
相关推荐
**JSF2学习笔记1——理解JavaServer Faces 2.0框架** JavaServer Faces (JSF) 是一种基于组件的Web应用程序开发框架,由Sun Microsystems(现为Oracle Corporation的一部分)开发,旨在简化用户界面构建。JSF2是该...
总之,“良葛格_JSF学习笔记”涵盖了JSF的基本概念、核心特性以及实践技巧,对于想要深入了解和掌握JSF的开发者来说,是一份非常有价值的参考资料。通过深入学习,你将能够熟练运用JSF构建高质量的Java Web应用程序...
而《Garfield的SCJP阅读笔记》.rar文件可能是关于Sun Certified Programmer for the Java SE Platform(SCJP)考试的学习资料,SCJP是Java开发者的基础认证,对于深化Java语言的理解大有裨益,但与JSF主题不直接相关...
JSF 是一种用于构建用户界面的模型-视图-控制器(MVC)框架,特别适合Web应用。本篇实战笔记主要补充了在JavaEE5中使用JSF的一些关键点,特别是关于流程转向和界面参数传递。 1. **流程转向**: 在JSF中,流程转向...
在Java企业版(Java EE)6的开发过程中,JSF(JavaServer Faces)2.0是用于构建用户界面的重要组件。这篇"jee6 学习笔记 5 - Struggling with JSF2 binding GET params"主要探讨了开发者在使用JSF2绑定GET参数时可能...
JSF 2.0规范(其中包含的JSF_20规范.pdf和JSF.pdf文档可能详细阐述了这一版本的特性)引入了许多改进,如异步处理、更强大的Facelets视图技术以及对CDI(Contexts and Dependency Injection)的支持,使得开发者可以...
JSF2.0在J2EE5中引入,进一步增强了其功能,如Facelets视图技术、复合组件支持和AJAX集成。 5. **持久化API (JPA)**:JPA是Java Persistence API,它是J2EE5的一部分,提供了一种标准的方式来管理和持久化Java对象...
9. **JSF入門.pdf**:这是一份JSF的基础教程,可能涵盖了JSF生命周期、组件模型、事件处理、渲染树等基础知识,适合JSF初学者。 10. **慣用句840.pdf**:这可能是840个常用的日语惯用句,对于提高日语水平和理解...
这个压缩包里涵盖了从基础到高级的各种主题,包括Hibernate学习笔记、J2EE全实例教程、JSF中文教程、Java设计模式、XML指南以及Struts2.0中文帮助手册等,对于想要深入理解J2EE框架和技术的开发者来说,无疑是一份...
AppFuse 是一个开源项目,旨在加速和简化J2EE应用程序的开发流程。由Matt Raible设计,它作为一...通过深入阅读和实践AppFuse的学习笔记,开发者可以逐步掌握其核心功能,并将其应用到实际项目中,提升开发质量和效率。
SCWCD,全称Sun Certified Web Component Developer,是Oracle(原Sun Microsystems)为Java开发者提供的一项专业认证,主要测试考生在构建动态Web应用程序方面的能力,包括Servlet、JSP(JavaServer Pages)、EL...