Tapestry的使用感受、经验及存在问题

本文介绍了Tapestry框架的特点、使用感受及优缺点,并详细探讨了其模板技术、池化技术、FriendlyURLs配置等内容,同时分享了一些使用经验和解决常见问题的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Tapestry的使用感受、经验及存在问题

一、Tapestry简介

    Tapestry是一个基于组件、监听事件的框架,它在web应用中的作用可以概括为“负责接受请求和产生HTML的响应”,它使用HTML模板、页面规范文件、对应的Java  page class通过ognl表达式(Object-Graph Navigation Language)的相关对象属性与Tapestry组件的绑定替代了传统web应用中的jsp,以致于有人形容它开发Web应用类似开发传统的GUI应用。有关Tapestry的详细信息可查看相关资料,此处不再过多赘述。

二、Tapestry使用感受

初步接触Tapestry时获得的信息是Tapestry基于具有监听事件的组件的开发,能够使用其组件实现类似于搭积木一样开发web应用,类似开发传统的GUI应用,并且页面采用Html模板可以达到所见即所得的效果,咋一听给人以很美妙、奇特的感觉,但实际使用过程中才真正的体会到,无论什么样的web架构,都没有本质的区别,都是基于最基本的JSP+SERVELT+JAVABEAN模式的,万变不离其中,可以说其开发模式和strutsspringMVC实质上是一致的;而Tapestry相对于其它开发框架的种种优点对开发人员的具体开发工作来说是很有限的(比如有人说:随着采用tapestry项目的深入,我们积累的各种积木也就越来越多,也就说,我们的工作越来越轻松,工作效率越来越高;但实际工作中却不是那么理想的),另外如果对Tapestry的基本原理了解的不是很透彻,使用Tapestry开发的将是效率低下、数据库压力巨大的web程序。

三、Tapestry的优点、使用经验杂谈

1Tapestry提供的模板技术非常好,对于模板的侵入性特别的低

  Tapestry可以让美工人员和开发人员尽可能的协同工作。这个优点恰恰是许多其它web框架的弱点。首先,利用可供利用的方便工具如DreamWeaver创建设计HTML页面,包括CSS,图片等。然后,在已经增加了动态内容的页面上修改,修改,再修改......直到客户满意为止。美工人员和开发人员之间的分工和协作能够起到很大的作用。

2Tapestry池化技术及page的初始化、入池、等待复用、调出复用的过程的个人理解

Tapestry池化技术深入理解有利于提高对tapestry的认识以及开发高效率的tapestry页面程序。因Tapestry是基于组件的,每个组件都是对象,在页面展示时对象都要实例化,tapestry的页面(page)也是组件, 为了提高效率tapestry采用了一种缓存机制,也就是页面池对page(页面)的实例进行缓存,以便复用,根据访问量的大小不同每个页面在页面池中的实例个数也有所不同。关于页面池的入池、出池的过程体现在page页面的Rendering过程中,如下图所示:

1page页面的Rendering过程图

需要注意的问题:a)如果page的属性不在initialize()方法中进行重置,如果保留属性值不重置是非常危险的,因为所有的page实例是完全共享的,另一个request完全有可能从池中获得上一个用户使用过的page,所以信息就会暴露。

                bpage rendering过程中调用的java page class 的方法根据实际情况要进行isrending()、 is nullisEmpty()等等相关的处理避免同一个逻辑或数据操作多次执行。

²        小讨论

Ø         观点Apage页面的rendering过程是组件化开发的体现,用起来灵活,效果不错。

Ø         观点B:正是page这样的rendering过程给了程序员犯错误的机会,如果处理不好的话,开发出来的将是效率低下、数据库压力巨大的web程序。

 

3page页面的Rewinding过程

rewind是用来处理表单提交的,tapestryformsubmitdirectlink等组件都具有listener,其listenerjava page class中的一个方法(监听方法)绑定,相关事件触发后开始page页面的Rewinding过程

  

2page页面的Rewinding过程图

需要注意的问题:在监听方法中一定要做好异常处理,并处理发生异常情况的页面的跳转问题。

²        小讨论

Ø         观点Atapestry组件的数据回写的方式不错,只要将相关DTO绑定到组件上,form提交后就不用操心从request中取数据了,直接访问DTO就有数据了。

Ø         观点B:这算什么呀,现在好多架构基于commons-beanutils等公共组件都能做到这一点。

Ø         观点Ctapestry的基于事件、监听方法的模式不错呀,这样的话很容易就做到同一个页面甚至是同一个表单中不同的业务处理请求分别转发到不同的业务处理方法体中。

Ø         观点D:这算什么呀,strutsspring也能做到。

4关于tapestry自定义组件

²        小讨论

Ø         观点Atapestry自定义组件不错,可以自定义复用的组件。

Ø         观点Bjsp不也有自定义标签吗,同样能到到自定义组件达到的效果。

5tapestryFriendly URLs的配置

  如果要访问contextpathnews目录中的Threads.html页面,需要通过地址/contextpath/app?page=news/Thread&service=page,这样的url即比较复杂又不能通俗易懂,通过一系列配置后可以使用/contextpath/news/Threads.htmlurl来访问

hivemodule.xml配置文件中加入

<contribution configuration-id="tapestry.url.ServiceEncoders">

       <page-service-encoder id="page" extension="html" service="page" />

       <direct-service-encoder id="direct" stateless-extension="direct"

           stateful-extension="sdirect" />

       <extension-encoder id="extension" extension="svc" after="*" />

       <asset-encoder id="asset" path="/assets" />

</contribution>

Web.Xml中加入

<servlet-mapping>

       <servlet-name>tapestryservet name</servlet-name>

       <url-pattern>*.html</url-pattern>

    </servlet-mapping>

    <servlet-mapping>

       <servlet-name> tapestryservet name </servlet-name>

       <url-pattern>*.external</url-pattern>

    </servlet-mapping>

    <servlet-mapping>

       <servlet-name> tapestryservet name </servlet-name>

       <url-pattern>*.direct</url-pattern>

    </servlet-mapping>

    <servlet-mapping>

       <servlet-name> tapestryservet name </servlet-name>

       <url-pattern>*.sdirect</url-pattern>

    </servlet-mapping>

    <servlet-mapping>

       <servlet-name> tapestryservet name </servlet-name>

       <url-pattern>*.svc</url-pattern>

    </servlet-mapping>

    <servlet-mapping>

       <servlet-name> tapestryservet name </servlet-name>

       <url-pattern>/assets/*</url-pattern>

</servlet-mapping>

6、把‘*.page’‘*.html’完全分开,不放在同一个目录下的方法

<page-specification >
    <asset name="$template" path="context:WEB-INF/pagepath/pageName.html"/>
</page-specification >

7Tapestry4.0.x版本的页面池实现很简单,只是使用一个map容器作为缓存,高并发的情况下容易导致OutOfMemoryException,解决方案如下:

添加java

package com.zzxy.typestry;

import java.lang.ref.SoftReference;

import java.util.HashMap;

import java.util.Iterator;

import java.util.LinkedList;

import java.util.List;

import java.util.Map;

import org.apache.tapestry.event.ReportStatusEvent;

import org.apache.tapestry.event.ReportStatusListener;

import org.apache.tapestry.event.ResetEventListener;

import org.apache.tapestry.services.ObjectPool;

/**

 * @author yanzhigang

 */

public class SoftReferenceObjectPool implements ObjectPool, ResetEventListener,

              ReportStatusListener {

       private String _serviceId;

       private int _count = 0;

       private Map _pool = new HashMap();

       public synchronized Object get(Object key) {

              List pooled = (List) _pool.get(key);

              if (pooled == null || pooled.isEmpty())

                     return null;

              _count--;

              SoftReference reference = (SoftReference) pooled.remove(0);

              // returns null if has been cleared by GC same as pool where empty

              return reference.get();

       }

       public synchronized void store(Object key, Object value) {

              List pooled = (List) _pool.get(key);

              if (pooled == null) {

                     pooled = new LinkedList();

                     _pool.put(key, pooled);

              }

              SoftReference reference = new SoftReference(value);

              pooled.add(reference);

              _count++;

       }

       public synchronized void resetEventDidOccur() {

              _pool.clear();

              _count = 0;

       }

       public synchronized void reportStatus(ReportStatusEvent event) {

              event.title(_serviceId);

              event.property("total count", _count);

              event.section("Count by Key");

              Iterator i = _pool.entrySet().iterator();

              while (i.hasNext()) {

                     Map.Entry entry = (Map.Entry) i.next();

                     String key = entry.getKey().toString();

                     List pooled = (List) entry.getValue();

                     event.property(key, pooled.size());

              }

       }

       public void setServiceId(String serviceId) {

              _serviceId = serviceId;

       }

}

hivemodule.xml配置文件中加入

<implementation service-id="tapestry.page.PagePool">  

     <invoke-factory>  

      <construct class="SoftReferenceObjectPool">  

      <event-listener service-id="tapestry.ResetEventHub"/>  

      <event-listener service-id="tapestry.describe.ReportStatusHub"/>  

      </construct>  

      </invoke-factory>  

    </implementation>  

    <implementation service-id="tapestry.GlobalObjectPool">  

     <invoke-factory>  

      <construct class="SoftReferenceObjectPool">  

      <event-listener service-id="tapestry.ResetEventHub"/>  

      <event-listener service-id="tapestry.describe.ReportStatusHub"/>  

      </construct>  

      </invoke-factory>  

    </implementation>  

    <implementation service-id="tapestry.request.EnginePool">  

     <invoke-factory>  

      <construct class="SoftReferenceObjectPool">  

      <event-listener service-id="tapestry.ResetEventHub"/>  

      <event-listener service-id="tapestry.describe.ReportStatusHub"/>  

      </construct>  

      </invoke-factory>  

    </implementation>  

四、Tapestry使用中存在的问题及风险

1、  Tapestry文档资料少,而实践项目少;学习曲线陡峭,采用Tapestry开发的项目添加项目成员的成本比采用其它框架的项目大。

2、  Tapestry的缓存机制不完善,存在导致web应用内存溢出的嫌疑。

3、  Tapestry api不稳定,不向下兼容,版本变化带来的api变化巨大,如Tapestry3.0Tapestry4.0Tapestry5.0的差别很大,甚至Tapestry4.0Tapestry4.1差别也比较大,这给项目升级带来了很大的困难。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值