宇凡's profileBreak the LoopPhotosBlogLists Tools Help

Blog


    May 14

    昨天测试了Tapestry里使用Hibernate PO,果然

    果然,当我将第一个页面中的City属性通过DirectLink传递给ShowCity页面后,当使用For组件显示City下的Suburb列表的时候,出现了LazyLoad异常。
    不过,也发现Tapestry的DirectLink似乎是把整个业务对象都encode到url里,不知道具体的实现如何,还有这样的link要是被用户bookmark了,下次访问的时候又会怎么样?似乎这样,即使使用了Long Conversation也没办法保证用户下次从收藏夹返回的时候,这个hibernate session还在,这样自然还是无法正确地得到他所需要的数据,照样会出异常。
    看来要想直接将Hibernate Entity传递到页面层已经不是一个正确的选择,似乎还应该使用DTO或者在使用session.lock()来重新attach实体对象。
    不过,session.lock向界面层透露了太多的底层信息,并且将web层和hibernate紧密地耦合在一起,自然不是一个好主意,这里DTO不应该再被当成反模式了,还是应该适当的使用。
    May 13

    Tapestry学习笔记第一篇

    1、Tapestry不是面向操作的、而是面向组件的。要理解tapestry,首先得理解组件对象模型(component object model),以及这段话:
    The "mantra" of Tapestry is "objects, methods and properties". That is, rather than have developers concerned about the paraphanlia of the Servlet API: requests, responses, sessions, attributes, parameters, URLs and so on, Tapestry focuses the developer on objects (including Tapestry pages and components, but also including the domain objects of the application), methods on those objects, and JavaBeans properties of those objects. That is, in a Tapestry application, the actions of the user (clicking links and submitting forms) results in changes to object properties combined with the invocation of user-supplied methods (containing application logic).
     
    2、Tapestry虽然让web开发变得和桌面应用开发十分相似,但由于HTTP协议本身的限制,还是有很多特殊的地方,有时候要结合两方面的经验来理解。
     
    3、在Tapestry中,一个Web APP由若干Page组成,而Page由若干组件组成,组件还可以包含其它组件,并没有层次的限制。Tapestry引擎会维护一个Page对象池,用户的每次请求都会从池中取得一个对象来处理。但正如前面所说,Tapestry的Page对象都是可以拥有状态,即你可以在Page类中定义属性,Tapestry4中的做法是定义一对abstract的getter/setter,然后利用Annotation指定属性的状态维持机制,如
    @Persist               默认在session中维持属性状态
    @Persist("client") 在client中维持属性状态,一般是把属性编码后存储在请求url中,不是很安全,也可能会造成集群环境中状态不一致(这里不是很理解具体原因,可能是我理解错误)。
    如果不指定@Persist,则必须由开发人员负责做好属性的初始化工作,一般是通过PageBeginRenderListener,然后在pageBeginRender事件中初始化,比如常见的做法是从业务层获取数据对象。注意,如果不做好初始化工作,可能会造成程序的行为非常怪异。
     
    个人觉得Tapestry中的属性和生命周期还是不太好理解,可能需要多做点试验,才能更好的理解。比如,定义一个具体的java bean属性,或者定义一个getXXX()方法,实际是从业务层得到数据对象,是不是效果和前面的方法一样?

    4、另外,利用H.L.S另外的一个在JavaForge上的Tapestry-Spring项目已经非常方便在页面注入业务层对象了,只需要定义个抽象的getXXX()方法,然后使用@InjectSpring("xxx")就能注入了。
     
    5、另外和Hibernate结合方面,总感觉没有找到好的办法,如果仅仅依靠OSIV,据说将PO定义为页面的属性,然后通过DirectLink传递给其他的页面使用时(是的,不用怀疑,Tapestry里可以在页面之间直接传递对像,而不需要你去重新组装对象,是不是感觉很OO?),会造成LazyLoad方面的异常,初步总结有三种办法,第一种是tapestry上提供的方法,但不太优雅,后两种是我自己在思考的,没有论证过:
    1、在pageBeginRender里,从新attach实体,使用session.lock(obj)
    2、利用DTO?, 虽然多了一层,但可能会省掉很多隐藏的问题。
    3、不使用OSIV,改为使用Long Session per conversation,这样用户的整个会话周期内都使用同一个hibernate session,就不会有这个问题。
    我思考的两种方法,前一种是将hibernate session的作用边界缩小到了业务层方法,往往是一个事物一个session,第二种是扩大到整个会话,一个会话一个session.不过,long conversation的方法使用起来比较复杂。如果不想让web层得到太多底层的细节,可能还是DTO比较好。