`
dengyin2000
  • 浏览: 1208544 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

原创 Tapestry的Cache组件

阅读更多
有许多页面的一部分或者这个页面是很少更新的,他们通常是由外部文件来生成这个部分。所以我们可以把这部分内容cache住,当有新的请求时,我们就response cache,这样可以减少服务器的负担,还可以提高性能。其中oscache已经可以实现页面的cache和页面部分cache。oscache使用jsp tags来实现局部cache的。拿到Tapestry中肯定是行不通的。在同事的提醒下,想到写这个Tapestry的cache组件来达到重用的目的。

说干就干,先在头脑中想好要怎样使用cache(页面上的布局)。ok。 我想好了。
xml 代码
 
  1. <span jwcid="@Cache" cacheProvider="ognl:cacheProvider" updateCondition="ognl:needUpdate">  
  2.   
  3.     //Cache body, which is the content you want to cache.  
  4.   
  5. <!---->span>  

这里有2个参数,updateCondition 当为true时,我们就绕过cache, cacheProvider 我把他定义为一个接口,这样用户可以把cache存在任何地方。而且提供这样的一个接口,用户可以更好的操作cache。先看看jwc对cache组件的定义。
xml 代码
 
  1. xml version="1.0" encoding="UTF-8"?>  
  2.   "-//Apache Software Foundation//Tapestry Specification 4.0//EN"   
  3.   "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">  
  4.   
  5. <component-specification allow-body="yes" allow-informal-parameters="no" class="com.live.spaces.dengyin2000.tapestry.tfancomponents.components.Cache">  
  6.     <description>  
  7.         Cache component, this component can inclue any content as its body, and cache its body.  
  8.         This is useful in rarely updated content.  
  9.     <!---->description>  
  10.     <parameter name="updateCondition" required="no" default-value="false">  
  11.         <description>  
  12.             The flag that need to refresh cache, it would casue tapestry render not use the cache.  
  13.         <!---->description>  
  14.     <!---->parameter>  
  15.     <parameter name="cacheProvider" required="yes">  
  16.         <description>  
  17.             You need to provider an cache provider to store its body content. for some simply use.  
  18.             Please see @com.live.spaces.dengyin2000.tapestry.tfancomponents.components.SimpleHtmlSourceCacheProvider  
  19.         <!---->description>  
  20.     <!---->parameter>  
  21. <!---->component-specification>  

下面的是ICacheProvider接口:
java 代码
 
  1. package com.live.spaces.dengyin2000.tapestry.tfancomponents.components;  
  2. /** 
  3.  * @author Denny - deng.yin@gmail.com 
  4.  * @since 2006-12-21 
  5.  */  
  6. public interface ICacheProvider {  
  7.       
  8.     /** 
  9.      *  
  10.      * @param cacheKey 
  11.      * @param cacheContent 
  12.      */  
  13.     public void storeCache(String cacheKey, String cacheContent);  
  14.       
  15.     /** 
  16.      *  
  17.      * @param cacheKey 
  18.      * @return 
  19.      */  
  20.     public String getCacheContent(String cacheKey);   
  21.       
  22.     /** 
  23.      * This method provider to user, so that user can controll cache manaully. 
  24.      * @param cacheKey 
  25.      */  
  26.     public void removeCache(String cacheKey);  
  27.       
  28.     /** 
  29.      * This method provider to user, so that user can controll cache manaully. 
  30.      * Clear all caches 
  31.      * 
  32.      */  
  33.     public void reset();  
  34.       
  35. }  

ok。 再来看看Cache组件的代码。
java 代码
 
  1. package com.live.spaces.dengyin2000.tapestry.tfancomponents.components;  
  2.   
  3. import java.io.PrintWriter;  
  4. import java.io.StringWriter;  
  5.   
  6. import org.apache.commons.logging.Log;  
  7. import org.apache.commons.logging.LogFactory;  
  8. import org.apache.tapestry.AbstractComponent;  
  9. import org.apache.tapestry.IMarkupWriter;  
  10. import org.apache.tapestry.IRequestCycle;  
  11. import org.apache.tapestry.util.ContentType;  
  12.   
  13. /** 
  14.  * @author Denny deng 
  15.  * 
  16.  */  
  17. public abstract class Cache extends AbstractComponent {  
  18.       
  19.     protected static final Log logger = LogFactory.getLog(Cache.class);  
  20.       
  21.     public abstract boolean getUpdateCondition();  
  22.       
  23.     public abstract ICacheProvider getCacheProvider();  
  24.       
  25.     @Override  
  26.     protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle) {  
  27.           
  28.         if (getUpdateCondition()){  
  29.             renderComponentWithCache(writer, cycle);  
  30.         }else{  
  31.             if (getCacheProvider().getCacheContent(this.getIdPath()) != null){  
  32.                   
  33.                 //response cache html content.  
  34.                 writer.printRaw(getCacheProvider().getCacheContent(this.getIdPath()));  
  35.             }else{  
  36.                 renderComponentWithCache(writer, cycle);  
  37.             }  
  38.         }  
  39.   
  40.     }  
  41.       
  42.     private void renderComponentWithCache(IMarkupWriter writer, IRequestCycle cycle) {  
  43.   
  44.         logger.debug("We need to refresh cache now.");  
  45.         CacheWriterWrapper cacheWrapper = new CacheWriterWrapper();  
  46.         super.renderBody(buildCacheMarkupWriter(cacheWrapper.getPrintWriter(), writer), cycle);  
  47.         String cacheContent = cacheWrapper.getCacheContent();  
  48.         logger.debug("fetched cache content, ready to put it into cache.");  
  49.   
  50.         getCacheProvider().storeCache(this.getIdPath(), cacheContent);  
  51.           
  52.         // response html content.  
  53.         writer.printRaw(cacheContent);  
  54.     }  
  55.       
  56.     private IMarkupWriter buildCacheMarkupWriter(PrintWriter writer, IMarkupWriter sourceWriter){  
  57.         return this.getPage().getRequestCycle().getInfrastructure().getMarkupWriterSource().newMarkupWriter(writer, new ContentType(sourceWriter.getContentType()));  
  58.     }  
  59.       
  60.     class CacheWriterWrapper{  
  61.         private StringWriter sw;  
  62.         private PrintWriter pw;   
  63.         public CacheWriterWrapper() {  
  64.             sw = new StringWriter();  
  65.             pw = new PrintWriter(sw);  
  66.         }  
  67.   
  68.         public String getCacheContent(){  
  69.             return sw.getBuffer().toString();  
  70.         }  
  71.           
  72.         public PrintWriter getPrintWriter(){  
  73.             return pw;  
  74.         }  
  75.     }  
  76. }  

主要是得到cache组件body的内容,然后把body的内容cache住,下次的话就response Cache的内容。 其实也是满简单的。

我自己还写了一个简单CacheProvider。

java 代码
  1. package com.live.spaces.dengyin2000.tapestry.tfancomponents.components;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5.   
  6. /** 
  7.  * @author Denny - deng.yin@gmail.com 
  8.  * @since 2006-12-21 
  9.  */  
  10. public class SimpleHtmlSourceCacheProvider implements ICacheProvider {  
  11.       
  12.     private Mapnew HashMap
  13.       
  14.     public String getCacheContent(String cacheKey) {  
  15.         return cache.get(cacheKey);  
  16.     }  
  17.   
  18.     public void storeCache(String cacheKey, String cacheContent) {  
  19.         cache.put(cacheKey, cacheContent);  
  20.     }  
  21.   
  22.     public void removeCache(String cacheKey) {  
  23.         cache.remove(cacheKey);  
  24.     }  
  25.   
  26.     public void reset() {  
  27.         cache.clear();  
  28.     }  
  29. }  
在使用中你可以把CacheProvider放到Global或者Visit对象中。注意要使用同一个CacheProvider。

 

我在google code host上面建了一个probject地址是http://code.google.com/p/tfancomponents/ 有兴趣的同学可以看看, 这是一个maven项目。

分享到:
评论
7 楼 dengyin2000 2007-08-10  
koda 写道
不错!我想知道你为什么不直接使用oschache呢?


本来我是打算用oscache来实现了。 其实oscache自己带了filter来处理cache。  我想尽量把他做简单点。 容易理解。  其实你可以看到  我的这个组件需要提供个CacheProvider。 这个是个接口。 所以这样的话, 你想使用任何cache都是可以的。 只要用你现在用的cache实现CacheProvider就行了。  这样岂不是更灵活???
6 楼 koda 2007-08-10  
不错!我想知道你为什么不直接使用oschache呢?
5 楼 dengyin2000 2006-12-22  
tapestry 写道
我的CacheContent意思是封装一个对象,里边有个开关变量,设定是否需要update,当然还有cache的内容(这个才是你的cacheContent的意思),里边有个update方法,因为总感觉update应该是cache自己的事情,但实验了一下概念还是比较乱,先暂时放放。
使用起来应该有两种情况,一种是设置页面的update开关,一种是cacheProvider的removeCache。试想这样一个场景,ShowBlogs页面,你cache住了,然后用户添加了blog,除非他添加完后直接需要到ShowBlogs页面,可以调用ShowBlogs.setNeedUpdate(true),然后显示ShowBlogs页面来刷cache,但一般情况很可能不是跳到ShowBlogs页面,可能是用户自己的ManageBlogs页面,这个时候更新的唯一方法就是调用cacheProvider.removeCache了。
cacheProvider里加个updateCache方法吧,方法里调用removeCache,这样api清楚点。


这里说说我的想法, 这个Cache主要是cache页面的,你想到的比较多,可能你忘了Cache组件中有个updateCondition 属性, 其实我是不太赞成ICacheProvider的removeCache这个方法的,这也是我开始想到使用idpath作为cacheKey的原因,用户不需要知道太多的东西。他仅仅需要知道什么时候我需要让tapestry重新生成一下Body的内容就行。 他也就需要实现updateConditon这个component方法。争对你说的这种场景, 我在updateCondition这个方法里面去判断数据库里面的最新帖子的时间和你生成cache时最新帖子的时间来比较(你可以保存在一个singtlon对象里面),如果时间更新了,return true就ok了。 其实我现在这个项目中也是这种情况,首页内容部分是由管理员upload的一个文件(owl file)生成的内容。这时候我在MiscUtils类里面有个checkOWLFileUpdated()方法去判断owl时候发生了变化, 也是使用file的lastmodfy time来判断的。 我在Cache组件中仅仅是非常方便的委派MiscUtils的那个方法而已。

你在上面也提到了主动的方式,就是在发表玩帖子的时候去设置updateCondition为true。其实你只要把这个值set到一个singlton类属性里面就ok了。 updateCondition方法就去check那个值吧。 我不是很赞成这种做法,因为他把一些非业务相关的逻辑加了进来,可能你会说我可以用aop方便的搞定这个。 但是我还是觉得判断cache是否要更新就让Cache组件来作罢(updateCondition)。
4 楼 tapestry 2006-12-22  
还有几点疑问,一个是tapestry本身就cache住了静态的模版文档,只需要动态内容添加进去然后生成页面,这个cache应该说是想将静态和动态内容cache住,不需要再生成了,既然是动态的必须是可被更新的,所以要给出个key来,好让人更新,老是调用页面去设置开关然后再显示好像不大方便,现在设置key的话就存在key的管理问题了,今天设定为news了,明天改了成newses了,好多地方就会更新不到了,设为enum或者常量都可以,一个数据字典的概念了,比如Home页面有3个cache了,分别是news,tags,links,后台更新数据的时候来看看哪里用了news了,更新下。这个扯远了,不过老是感觉还有改进的可能,但又暂时想不到。
3 楼 tapestry 2006-12-22  
我的CacheContent意思是封装一个对象,里边有个开关变量,设定是否需要update,当然还有cache的内容(这个才是你的cacheContent的意思),里边有个update方法,因为总感觉update应该是cache自己的事情,但实验了一下概念还是比较乱,先暂时放放。
使用起来应该有两种情况,一种是设置页面的update开关,一种是cacheProvider的removeCache。试想这样一个场景,ShowBlogs页面,你cache住了,然后用户添加了blog,除非他添加完后直接需要到ShowBlogs页面,可以调用ShowBlogs.setNeedUpdate(true),然后显示ShowBlogs页面来刷cache,但一般情况很可能不是跳到ShowBlogs页面,可能是用户自己的ManageBlogs页面,这个时候更新的唯一方法就是调用cacheProvider.removeCache了。
cacheProvider里加个updateCache方法吧,方法里调用removeCache,这样api清楚点。
2 楼 dengyin2000 2006-12-22  
tapestry 写道
这个idea不错,还有扩展的余地,保存的key最好不要用idPath,自己可以定义,例如定义一个cache名字为news,key应该为Home:news,这样我可以使用cacheProvider.update("Home:news")来更新,还可以写个annotation,例如我新建了个news,
@InjectCache("Home:news")
public CacheContent getHomeNewsCache();

public void save(){
   getNewsService().save(getNews());
   getHomeNewsCache().update();
}
这样可用性比较好,有兴趣的话,一起研究一下。


开始时我觉得这个cacheKey其实可以对用户不见的,用户不用关心cache的内容。其实这里的cache的内容也就是cache组件的body render之后的html source。但是ICacheProvider提供了removeCache这个方法。假如用idPath的对用户来说确实是不友好的。 指定cacheKey值的话,可读性也很高。这个想法不错。我会加入这个功能,多加个cacheKey属性,假如用户关心的话就指定, 不指定的话默认就是idpath。
<span cacheProvider="ognl:cacheProvider" cacheKey="literal:Home:news"   updateCondition="ognl:needUpdate">
//body  ....
</span>

@InjectCache("Home:news")
public CacheContent getHomeNewsCache();

你这个annotation的意思是获得cache的内容么? 我这里可能有多个cacheProvider, 而且我想用户可以方便的通过cacheProvider去拿到cache content。 再者我想用户肯定不会想去自己updateCache的内容,因为这个body是tapestry解析后的内容,我想用户关系的只是现在cache中的内容是不是stale的。我现在需不需要更新这个cache。 获得cache的内容交给tapestry来处理。 其实这个组件的目的也是主要是想cache页面的html source而已。

现在想要更新cache中的内容的话, 你只需要让updateCondition为true, 或者让对应的cache 内容为null 即可。

非常谢谢tapestry提供的建议,欢迎一起研究。
1 楼 tapestry 2006-12-22  
这个idea不错,还有扩展的余地,保存的key最好不要用idPath,自己可以定义,例如定义一个cache名字为news,key应该为Home:news,这样我可以使用cacheProvider.update("Home:news")来更新,还可以写个annotation,例如我新建了个news,
@InjectCache("Home:news")
public CacheContent getHomeNewsCache();

public void save(){
   getNewsService().save(getNews());
   getHomeNewsCache().update();
}
这样可用性比较好,有兴趣的话,一起研究一下。

相关推荐

    Tapestry的组件及功能

    介绍Tapestry组件的使用和功能。内容还行,使用初学者入门。

    tapestry5 自定义组件

    自定义的邮件组件!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    tapestry组件

    tapestry部分组件绑定参数的列表!

    tapestry页面编辑组件

    tapestry页面编辑组件,可以实现文本框,单选框,多选框和下拉框等的自动生成,并返回改变后的数据。

    tapestry4.02中封装ext的GridPanel组件

    tapestry4.02中封装ext的GridPanel组件

    tapestry5中文文档

    tapestry5组件说明使用及登陆修改等简单实例

    tapestry 5.1.0.5 官方组件文档 天涯浪子

    来自:http://tapestry.apache.org/tapestry5.1/tapestry-core/ref

    tapestry hibernate Spring应用及组件的使用

    tapestry hibernate Spring应用及组件的使用的一个简单完整例子,包含form组件、table组件的一个增删改查。其中数据库创建用户和表在docs里,数据库使用oracle

    Tapestry简单入门.rar_java Tapestry_tapestry

    Tapestry简单入门介绍,包含Tapestry入门、tapestry组件介绍

    Maven + Tapestry5.3.8 + Spring4.0.5 + Oracle10g

    2)Tapestry 各种核心组件的使用 3)自带验证,自定义验证,验证码的生成 4)Tree组件的使用,Grid的各种使用(修改样式,排序,隔行换色等等),Loop组件的使用 5)集合Spring4.0.5实现的增删改查 等等 如果你是新...

    tapestry技术

    Tapestry是一个开源的基于servlet的应用程序框架,它使用组件对象模型来创建动态的,交互的web应用。一个组件就是任意一个带有jwcid属性的html标记。其中jwc的意思是Java Web Component。Tapestry使得java代码与html...

    tapestry教程资料文档合集

    Tapestry5最新中文教程.doc 作者 Renat Zubairov & Igor Drobiazko译者 沙晓兰 发布于 2008年7月2日 下午9时30分 社区 Java 主题 Web框架 ----------------------------------------- Tapestry5.1实例教程.pdf ...

    Tapestry开发指南

    Tapestry是一个开源的基于servlet的应用程序框架,它使用组件对象模型来创建动态的,交互的web应用。一个组件就是任意一个带有jwcid属性的html标记。其中jwc的意思是Java Web Component。Tapestry使得java代码与html...

    Tapestry5开发文档手册.doc

    tapestry5组件说明使用等简单实例。Apache Tapestry是一个使用Java语言创建web应用的面向组件的开发框架。Tapestry应用建立在根据组件构建的页面的基础上。这个框架能够提供输入验证(input validation)、本地化/...

    深入浅出Tapestry

    资源名称:深入浅出Tapestry内容简介:本书以循序渐进的方式,从Tapestry框架技术的基本概念入手,讲解Tapestry框架在J2EE Web应用程序中的整体架构实现。使读者在学习如何使用Tapestry框架技术的同时,还能够获得在...

    Tapestry5最新中文入门实例教程

    本文介绍Tapestry框架版本5。本文利用Tapestry 5开发一个简单的具有创建/读/更新/删除功能的应用,在创建这个应用的过程中,本文体会到Tapestry...还将了解如何应用Tapestry中内嵌的Ajax功能来创建支持Ajax的组件。

    tapestry官方中文文档

    Tapestry 4 官方文档中文版本,现在中文资料比较少,和大家共享一下

    tapestry5以上的帮助事例,帮助文档与spring衔接文档

    Tapestry是一个基于控件的框架以致于用它开发Web应用类似开发传统的GUI应用。你用Tapestry开发Web应用时你无需关注以操作为中心的(Operation-centric) Servlet API.引用Tapestry网站上的一句话:"Tapestry用对象...

    tapestry 实例

    tapestry 实例tapestry 实例tapestry 实例tapestry 实例

    Tapestry5.0.16_API文档

    Tapestry5.0.16文档和大家一起学习

Global site tag (gtag.js) - Google Analytics