|
二、不同的JSF AJAX方法
如果你不想使用其它附加功能,那么不必改变JSF组件层次,因此也不需要经历整个JSF生命周期。但是,如果你想重用一个托管bean方法,那么最容易的方式就是使用JSF MethodBinding工具。为此,存在三种方案:把功能添加到Renderer,使用一个PhaseListener以及提供一种新的JSF生命周期。
三、Renderer方法
Renderer方法把功能添加到屏幕生成器以检测AJAX请求。JSF默认的生命周期首先在“Restore View”阶段恢复组件层次,而在“Apply Request Values”阶段Renderer获得控制。在处理完AJAX请求后,Renderer调用FacesContext的responseComplete()方法来终止处理生命周期的剩下阶段。从表面上来看,这似乎是一种更好的方法,但是它实际上存在一些严重的不足。
首先,这种方法要求有一个组件层次,这可能导致在每个请求中带来其它额外开销,特别是当使用客户端状态保存功能时。仅当这一阶段处理完之后,调用response-Complete()方法才起作用。这个“Apply Request Values”阶段调用视图中所有屏幕生成器上的decode()方法,这有可能导致不期望的超出控制的“副作用”,例如由应用程序开发者把一个<h:commandButton>设置为immediate="true"。这将导致在“Apply Request Values”阶段完成之前调用应用程序逻辑。
另外,这种方法通常需要使用HTTP POST来把状态字符串发送回服务器端。
四、PhaseListener方法
这个PhaseListener方法添加一个PhaseListener(PhaseId.RESTORE_VIEW)—它“短路”生命周期并且完成在PhaseListener本身中的所有处理工作。此后,它要调用FacesContext的responseComplete()方法。
为使这种方法能够工作,它必须生成一个包含在初始请求中有关使用托管bean信息的引用。PhaseListener在回寄期间使用这个信息以创建一个MethodBinding—然后,它被用于调用托管bean上的一个方法并且把数据返回到客户端。既然没有创建组件层次而且没有屏幕生成器,那么把immediate设置为true的命令组件就不会导致任何副作用。
但是,这种方法存在一个问题:无法防止应用程序开发者在同一阶段依附其它的PhaseListeners,这样可能导致不希望的副作用。而且,你也无法知道这些PhaseListeners将以怎样的顺序执行。
五、生命周期方法
这个生命周期方法添加一个被映射到一个AJAX请求的新的生命周期并且仅包含需要处理请求的生命周期阶段,调用由MethodBinding所定义的应用程序逻辑,并生成响应。这消除了创建和恢复组件树的麻烦,因此不需要屏幕生成器。如果把immediate设置为true,你也不会遇到任何问题。
使用一种定制的生命周期的另一项优点是,由应用程序开发者添加的任何PhaseListener对这种方案都将毫无影响;应用程序开发者甚至能把PhaseListeners添加到这个定制的生命周期。然而,如果使用一个定制PhaseListener把其它托管beans加入到该请求上,那么你可能遇到一些问题,除非它们也为此定制的生命周期进行了注册。 |
|