`
kidneyball
  • 浏览: 328993 次
  • 性别: Icon_minigender_1
  • 来自: 南太平洋
社区版块
存档分类
最新评论

JSF 2.0阅读笔记:视图状态 (二)

阅读更多
(续一)

三、可能的优化方案

撇开JSF2.0不谈,不妨先来想想针对JSF1.2的问题,有哪些可能的优化方案?

1. 组件的底层实现应改用可统一管理的,按名访问的,动态的弱类型属性集合。说白了,就是在组件类中用一个统一的Map来管理组件属性值。相对于强类型对象域,这种方法虽然在理论上会导致属性访问性能降低,但同时会给采集组件状态的性能带来提升,因为现在只需要采集被显式设置过的组件属性,而不是组件上的所有属性。进而,对后续的编码/解码速度,视图状态大小等等性能参数带来提升。并且,可以对saveState与restoreState的逻辑进行抽象,提升到继承层次更高的基类中甚至API中实现,而不需每个具体的组件类自行去覆盖。

2. API支持与业务逻辑无关的视图声明语言(例如Facelets),JSF引擎通过视图定义语言可随时获取到视图的初始状态。基于初始状态,对需要实际保存的视图状态进行优化。优化的方案有很多种,包括:

a. 增量视图状态。视图状态中仅保存当前组件树状态与初始状态的差异信息。在恢复组件树时,先通过视图声明语言获得视图初始状态,再根据视图状态中的差异信息进行调整,最终获得实际的当前组件树状态。这种方案的优点是在保持对应用开发者隐藏视图状态概念的同时,大幅降低了仅对组件树作少量局部修改的场景下的视图状态尺寸。对于动态性较强的页面,例如页面上仅放一个f:view,整棵组件树都是在运行期动态生成的场景,则提升不大。

b. 局部视图状态。视图状态中仅补存当前组件树状态的局部信息。在恢复组件树时,先通过视图声明语言获得视图初始状态,在根据视图状态中的局部信息进行调整,最终获得实际的当前组件树状态。这种方案需要把视图状态的概念暴露给应用开发者,应用开发者需要通过某种方式在组件树中指定需要保存的部分,并且必须清楚认识到,对于不保存的部分,每次请求开始时都会恢复为初始状态,在请求后续处理中所作的修改不能保留到下一请求中。此外,对于某些功能复杂的组件,很可能存在一些属性值是必须跨请求保持的,否则将导致其无法正常工作,例如说分页组件的当前页数。对于这些必须保存的状态,引擎需要提供机制上的支持,并且提供接口让组件开发者能方便地定义这些必须保存的属性。显然,这种方案会侵入组件开发者和应用开发者现有的编程模型,迫使他们必须关注视图状态的概念。但是,优势也是明显的,应用开发者拥有了对视图状态的完全控制能力。在大多数视图状态不会发生改变场景中,他可以指定根本不保存视图状态。

c. 分离视图状态。前面说过,JSF1.2支持让开发者选择把视图状态保存在服务器端还是客户端。在实际应用中,这种非黑即白的二分法只会让开发者顾此失彼,要么完全牺牲内存,要么完全牺牲带宽。但话又说回来,这种“以带宽换内存”的思路大体上是合理的,前提是,在换的比例上应能平滑过渡,而不是非此即彼。比如说,对于带宽吃紧的环境,应允许配置为“最多允许100k的视图状态传递到客户端,超出的保存在服务器端session中”,或者“40%的视图状态传递到客户端,60%保存在服务器端session中”等等。

需要注意的是,以上的a、b、c三种方案,并不是互斥的,完全可以结合起来使用。例如可以有局部增量视图状态,也可以把增量视图状态分离保存。

四、JSF2.0中的视图状态

现在开始进入正题(传说中的三纸无驴?),JSF2.0提供了怎样的视图状态方案。

简单来说,JSF2.0提供了上面优化方案中的1和2a,也就是统一的弱类型属性集合,和增量视图状态。但其中增量视图状态在规范中被称为PartialState(局部状态),为了避免歧义,下文中仍然称其为增量视图状态。

结合JSF 2.0的API与参考实现(Mojarra项目)来看,与视图状态相关的类关系大致如下:



其中,绿色为API中的接口和基类,黄色为RI中的实现类。

图中可以看出JSF 2.0中视图状态处理的主线流程。前面提到过,StateManager是视图状态处理的主入口。在图中可以看出,RI中有两个时机触发生成视图状态信息。一是在Form组件的渲染器中,调用ViewHandler的writeState方法,该方法则负责调用StateManager的writeState方法进入生产视图状态的流程。当页面刷新时,走这条路径。二是在PartialViewContext的processPartial方法中,直接调用StateManager的getViewState方法获取已编码的视图状态信息字符串。当渲染Ajax响应时,走这条路径。

StateManager的实现类主要负责视图状态的收集和恢复过程。针对生产视图状态,StateManager提供了writeState与getViewState两个接口方法,其中writeState负责在收集好当前组件树状态信息后,调用ResponseStateManager进行编码和输出,而getViewState方法则只以字符串方式返回编码后的视图状态信息,并不实际向响应流中输出。

在JSF2.0之前的版本,收集和恢复的逻辑直接由StateManager的实现类负责。JSF2.0中加入了VDL的概念,因此在这里把收集和恢复代理给当前ViewDeclarationLanguage所持有的StateManagementStrategy实例来完成。换句话说,通常情况下在JSF2.0中视图状态的收集和恢复逻辑的入口,在StateManagementStrategy的实现类中;编码和解码逻辑的入口,在ResponseStateManager的实现类中。

StateManagementStrategy提供了两个抽象方法:

public abstract class StateManagementStrategy {

    public abstract Object saveView(FacesContext context);

    public abstract UIViewRoot restoreView(FacesContext context, String viewId,
                                           String renderKitId);
}


其中saveView方法的实现负责遍历组件树。把组件树的当前状态收集到一个可序列化数据结构中返回。在JSF2.0之前版本,API上硬编码了该结构至少应包括组件树结构(TreeStructure),组件属性(Attributes),与附加对象(AttachedObject)三部分。从JSF2.0版本开始,在API代码层面上去除了对该数据结构的限制。

restoreView方法则负责从视图状态中恢复出组件树。对于这个方法,API通过javadoc详细指明了实现步骤。实现类应先从页面(markup)中构造出原始的组件树,对于自动生成的组件id,必须与首次请求时所生成的id一致。然后调用ResponseStateManager上的getState方法(解码)获取到与上次请求中调用saveView方法所返回的数据结构一致的视图状态信息。最后,根据这个视图状态信息对先前构造的原始组件树进行调整,最终得出实际的组件树,返回其根节点。

从这里的javadoc可以看出,JSF2.0 API所推荐的视图状态方案,就是增量方案。顺带一提,我个人觉得在API的javadoc上写这种实现细节并不妥当,难道别人的实现不用增量视图状态就不符合规范了吗?说不定有比增量方案更好的呢?

以上是处理视图状态的主线流程,下面具体来看看JSF2.0是如何实现弱类型属性集合和增量视图状态的。

4.1. 弱类型属性集合

从上面的类图中的“组件状态关系结构”部分可以看出,所有组件(UIComponent是所有组件的公共基类)都实现了PartialStateHolder接口,而PartialStateHolder又继承自StateHolder接口。这个StateHolder是什么?简单来说,就是希望在JSF视图状态中保存自身状态,并且希望控制自身状态的采集和恢复过程的类必须实现的接口。StateHolder提供了两个经典接口方法:
public Object saveState(FacesContext context);

public void restoreState(FacesContext context, Object state);


StateManagementStrategy在收集视图状态时,事实上是通过遍历组件树,调用各个组件上的saveState方法来获取组件的当前状态的。因此组件可以覆盖此方法,控制自身的状态应包括哪些属性值和保存的方式。restoreState则是saveState的逆操作,负责根据上一次调用saveState所收集的组件状态数据,来恢复组件的属性值。

StateHolder对于组件开发者来说是一个非常重要的接口,除了组件以外,任何希望在视图状态中保存的附加对象,都可以考虑实现该接口,例如Validator等等。JSF规范中规定(Sec7.7.1)

引用
Validators, Converters, FacesListeners, and other objects attached to a component. The manner in which these attached objects are saved is up to the component implementation. For attached objects that may have state, the StateHolder interface (see Section 3.2.4 “StateHolder”) is provided to allow these objects to preserve their own attributes and properties. If an attached object does not implement StateHolder, but does implement Serializable, it is saved using standard serialization. Attached objects that do not implement either StateHolder or Serializable must have a public, zero-arg constructor, and will be restored only to their initial, default object state.


简单来说,就是任何一个附加到组件上对象,在保存/恢复状态时,优先考虑是否实现StateHolder接口,如是则调用saveState/restoreState来处理。否则,看是否可序列化,如是则通过序列化方式保存。如果均没有,则只调用其默认构造器,构造出一个初始状态的对象。

从类图中可以看到,UIComponent持有另一个StateHolder的子接口,StateHelper。而且API提供了该接口的默认实现:ComponentStateHelper。这个就是前面所说的弱类型属性集合了。

(待续)
  • 大小: 195.4 KB
1
2
分享到:
评论
1 楼 zdmcjm 2011-08-31  
精彩!!!!!这样的文章很少见。

相关推荐

    一个简单的jsf例子------JSF2学习笔记1

    **JSF2学习笔记1——理解JavaServer Faces 2.0框架** JavaServer Faces (JSF) 是一种基于组件的Web应用程序开发框架,由Sun Microsystems(现为Oracle Corporation的一部分)开发,旨在简化用户界面构建。JSF2是该...

    良葛格_JSF学习笔记.rar

    `FacesContext`是JSF框架的核心上下文对象,它在JSF生命周期中贯穿始终,提供了对请求、响应和应用程序状态的访问。Managed Beans是JSF中的业务逻辑组件,通过`@ManagedBean`和`@RequestScoped`等注解来声明和管理。...

    《JSF入门》简体中文版.rar

    而《Garfield的SCJP阅读笔记》.rar文件可能是关于Sun Certified Programmer for the Java SE Platform(SCJP)考试的学习资料,SCJP是Java开发者的基础认证,对于深化Java语言的理解大有裨益,但与JSF主题不直接相关...

    JavaEE5实战笔记04JSF的一些补充

    本篇实战笔记主要补充了在JavaEE5中使用JSF的一些关键点,特别是关于流程转向和界面参数传递。 1. **流程转向**: 在JSF中,流程转向通常通过`faces-config.xml`文件中的`<navigation-rule>`元素来定义。例如,当...

    jee6 学习笔记 5 - Struggling with JSF2 binding GET params

    在Java企业版(Java EE)6的开发过程中,JSF(JavaServer Faces)2.0是用于构建用户界面的重要组件。这篇"jee6 学习笔记 5 - Struggling with JSF2 binding GET params"主要探讨了开发者在使用JSF2绑定GET参数时可能...

    JSF+Spring+Hibernate相关技术文档

    JSF 2.0规范(其中包含的JSF_20规范.pdf和JSF.pdf文档可能详细阐述了这一版本的特性)引入了许多改进,如异步处理、更强大的Facelets视图技术以及对CDI(Contexts and Dependency Injection)的支持,使得开发者可以...

    【读书笔记】Java参考大全-J2EE5版本

    JSF2.0在J2EE5中引入,进一步增强了其功能,如Facelets视图技术、复合组件支持和AJAX集成。 5. **持久化API (JPA)**:JPA是Java Persistence API,它是J2EE5的一部分,提供了一种标准的方式来管理和持久化Java对象...

    清晰的技术资料学习笔记

    3. **二級試験用単語 .doc**:这可能是指日本的二级IT资格考试的词汇清单,帮助考生准备考试,涵盖了考试中可能出现的专业词汇。 4. **Seam_2.0_Reference_zh_CN.pdf**:Seam是一个Java EE(企业版Java)框架,专注...

    j2ee体系chm帮助文档大全

    这个压缩包里涵盖了从基础到高级的各种主题,包括Hibernate学习笔记、J2EE全实例教程、JSF中文教程、Java设计模式、XML指南以及Struts2.0中文帮助手册等,对于想要深入理解J2EE框架和技术的开发者来说,无疑是一份...

    appfuse 学习笔记

    AppFuse 是一个开源项目,旨在加速和简化J2EE应用程序的开发流程。由Matt Raible设计,它作为一...通过深入阅读和实践AppFuse的学习笔记,开发者可以逐步掌握其核心功能,并将其应用到实际项目中,提升开发质量和效率。

    SCWCD-083资料

    3. **EL(Expression Language)**:EL是JSP 2.0引入的简洁表达式语言,用于访问JavaBean属性和执行基本操作。掌握EL变量,操作符,函数和上下文对象的使用。 4. **JSTL(JavaServer Pages Standard Tag Library)*...

Global site tag (gtag.js) - Google Analytics