技术开发 频道

Tapestry内部工作原理

    把Page实例返回池

    在request结束时,response被发送回client之后,附着在request上的page必须被返回池,页面属性包括持久的临时的都必须被重置回初始值,以供其他用户的request使用。如果保留属性值不重置是非常危险的,因为所有的page实例是完全共享的,另一个request完全有可能从池中获得上一个用户使用过的page,所以信息就会暴露。IRequestCycle的cleanup()方法Figure 7.21,会释放所有他拥有的资源,就包括释放page回page source,过程如下:
    1).调用IPageSource的releasePage(IPage page)方法
    1.1).IPage的detach()方法
    1.1.1).清除changeObserved属性,Clears the changeObserved property
    1.1.2).调用所有注册的相关监听器的PageDetachListener.pageDetached(PageEvent)
    1.1.3).调用org.apache.tapestry.AbstractPage.initialize()清除重置所有属性
    1.1.4).Clears the engine, visit and requestCycle properties,the page's visit,engine,and requestCycle properties are reset to  null.

    子类可以覆写这个方法,但是必须在子类方法中调用父类的同名方法,通常是在方法的最后(以上detach()说明主要参见AbstractPage.detach()方法API文档)
实际上只要你用<property-specification>元素来声明持久或临时属性,就不必关心页面的清除工作, detach()或initialize()方法主要是早期版本中要顾及的。

    页面呈现过程:

    tapestry呈现的核心是IRender接口,只有一个方法: public void render(IMarkupWriter writer, IRequestCycle cycle);
这个接口被希望参与页面呈现处理的所有对象所实现,他是IComponent的父接口,因此所有的部件都可以被呈现。IMarkupWriter接口一个很重要的工作,把所有xml保留字自动转换,如><等,不用程序来干预。BasePage类实现了 getResponseWriter(),源码为:

public IMarkupWriter getResponseWriter(OutputStream out) { return new HTMLWriter(out, getOutputEncoding()); }

     HTMLWriter的getContentType()方法默认会返回一个字符串“text/html; charset=UTF-8”,因此若要返回xml类型,应该在BasePage的子类中覆写getResponseWriter()方法,如下:

public IMarkupWriter getResponseWriter(OutputStream out) { return new HTMLWriter("text/xml",getOutputEncoding(),out); }

    若要返回wml类型,应该在BasePage的子类中覆写getResponseWriter()方法,如下:

public IMarkupWriter getResponseWriter(OutputStream out) { return new WMLWriter(out, getOutputEncoding()); }

    engine对象的renderResponse()方法:
    1).调用IRequestCycle对象的getPage(),得到page对象
    2).调用page对象的public IMarkupWriter getResponseWriter(OutputStream out)方法,返回一个IMarkupWriter对象
    3).调用IMarkupWriter对象的getContentType(),这个值用来设置HttpServletResponse的setContentType()方法
    4).调用IRequestCycle对象的renderPage(IMarkupWriter writer),呈现指定的页面,应用应该总是用这个方法来呈现页面,而不是直接调用IRender.render(IMarkupWriter, IRequestCycle),因为在呈现之前cycle对象必须进行一些设置;
    4.1).IRequestCycle对象的renderPage()调用page对象renderPage(IMarkupWriter writer,IRequestCycle cycle),被调用来呈现完整页面,这个方法应该只由IRequestCycle.renderPage(IMarkupWriter writer)调用,这个方法内执行呈现的具体过程如下Figure 7.18
    4.1.1).调用PageRenderListener的pageBeginRender(org.apache.tapestry.event.PageEvent)方法
    4.1.2).调用page对象的beginResponse(IMarkupWriter, IRequestCycle),这是最后一次机会可以修改持久属性
    4.1.1).回调IRequestCycle的commitPageChanges()方法,这个方法会通知负责持久属性管理的page recorders进行相应的保存
    4.1.1).调用page对象的render(IMarkupWriter, IRequestCycle),page开始呈现他的模板的内容,同样的递归呈现他包含的部件
    4.1.1).调用PageRenderListener的pageEndRender(org.apache.tapestry.event.PageEvent) (this occurs even if a previous step throws an exception).


一旦呈现页面开始,持久页面属性就不能再被修改!!!

    页面属性

    声明的属性,持久的、临时的都可以有一个初始值,初始值或者是<property-specification>元素的"initial-value"属性的值,或者是<property-specification>元素体的内容,初始值是OGNL表达式,此表达式只被计算一次并且表达式的值被保存起来,是在page或component的finishLoad()方法被调用之后。表达式的值被用来给属性赋初值,当page被从request拆开时,为复用返回page池之前,此表达式的值被用来更新属性。初始值也可以不在<property-specification>元素指定,可以在finishLoad()方法内设置,finishLoad()方法调用完毕,tapestry框架会读这个属性,读出的值就将是属性的初值,会被保存为以后用,当page拆开时返回前,此保存的初值会被重新赋给属性,也就是说,无论是在initial-value或者是在finishLoad()中,都可指定初值,然后此初值被tapestry保存用于为属性恢复初值!

0
相关文章