JAVAWEB缓存技术

时间:2024.5.13

JAVAWeb应用缓存技术资料收集与总结

                                                                                       ——作者:夏俊时间:20##-1-2

WEB用户行为分析系统上线,在测试某些功能时候,发现部分功能响应时间过长,比如对起点文学的按月的统计数据显示,响应时间超过了3秒,这个不太符合用户的需要,那么接下来就是优化系统,提高系统速度的工作。我们在分析响应速度缓慢的原因,发现还是数据库处理数据这块原因,究其根本还是数据量过大的原因,而且在数据库层面已经速度这块很难再有提升,因此考虑到web的缓存技术,这些响应速度缓慢的功能基本都是按周,按月的统计数据,因此在单位时间内的缓存是完全可以实现,以下就是我收集的java web缓存的相关技术,有两个技术重点推荐,一个是OSCache,一个是JCS,这两个是缓存技术里应用最为广泛的,也是最为成熟并且是开源的技术。

下面是我推荐这两种技术的原因,如下:

1)        都是开源的JAVA程序

2)        网上能找到比较丰富的资料

3)        都支持分布式的系统

4)        操作部署都不太难

5)        均符合我们现在系统开发的需要

OSCACHE和JCS区别在哪里了?现在我都只是简单看了下,现在总结还不全面,等具体操作后会加以补充:

1)        OSCache我找到的资料,我感觉主要是是页面级的缓存,他的缓存开发代码基本都是在页面里,用标签定义,应该数据都是缓存在客户端(这点还要细细体味)

2)        JCS是服务端的缓存,他基本是将需要缓存的数据先存在服务器的内存或是硬盘里,在一定时间内用户可以不通过数据库这个线路获取数据,而是从服务器直接获取,但这样会不会服务端负荷过大

从以上区别来说,如果数据能在客户端缓存,我还是更加推荐点,但是客户端如果缓存,用户要是有什么原因经常清理客户端缓存也是个问题。

最后这几种缓存技术和我们现在系统的整合的问题,这个我还要接着找下数据,我们系统是struts2+jquery(service和DAO层,这个缓存应该不会牵涉到),JCS是服务端缓存,所以数据返回可以在action里封装,对于前台而言影响不大,至于OSCache,如果使用它那么系统该如何改造,这个我要考虑下。

再有就是何时来缓存数据,就是触发缓存的方式,是用户的第一次在适当时间的点击还是通过调度的方式定时缓存了,这点也要考虑下。

写以上内容发现自己刚才对OSCache没有理解太清楚,OSCache缓存是使用标签的,在标签里的内容就会按时间缓存。因此实际操作下是很重要的。

(一)  第一份资料—JCS

Java 缓存系统(Java Caching System,JCS)

a)     资料编号NO101

JCS概述:JCS 是一个用 Java 语言编写的缓存系统,可以使用它来创建 Java 桌面和 Web 应用程序。它提供了在缓存器中存储数据、从缓存器中删除数据等方便机制。使用 JCS 可以在各种指定的数据区域 中存储缓存数据。JCS 定义了 4 种类型的核心区域:内存区域、磁盘区域、外围区域和远程区域。可以结合使用这些核心区域以在如何存储缓存数据、将缓存数据存储在什么地方等方面获得更大的灵活性。您可以指定首次使用哪个区域,以及发生故障时转移到哪个区域。

内存区域:内存区域是一个使用最近最少算法(Least Recently Used,LRU)的纯内存缓存区域。当内存缓存区域满时,LRU 会首先删除最近最少使用的缓存数据。这个数据区域执行良好,大多数 JCS 用户将它指定为最先使用的默认缓存区域。

磁盘区域:磁盘区域是在 Web 服务器的文件磁盘上缓存数据。为了提高性能,JCS 在文件磁盘上存储实际缓存数据的同时,会在内存中存储缓存数据键。在首先使用内存区域的典型 JCS 配置中,任何无法在内存区域中保存的数据都会写入磁盘区域中。

外围区域外围区域提供一种可配置方式来在多台服务器之间分发缓存数据。缓存数据服务器必须有一个开放的用于侦听的端口,而且必须创建一个套接字连接。这个区域存在一个潜在问题,因为它不能保证各缓存之间的数据的一致性。但如果是按计划使用该区域,则不会出现这个问题。

远程区域远程区域提供了一个使用远程方法调用(RMI)API 的缓存区域。这个区域使用一台远程服务器处理缓存数据。这台远程缓存服务器可以被多个 JCS 客户端应用程序用于存储缓存数据。一些侦听器被定义用于收集来自客户端和服务器的请求。这个缓存区域帮助减少串行化和多个连接点的开销。

JCS 的可插入控制器:JCS 通过组合缓存器(Composite Cache)让使用多个区域进行缓存存储变得很简单。组合缓存器为缓存区域提供了一个可插入控制器。组合缓存器仔细处理复杂的任务,即确定何时以及如何使用每个缓存区域。JCS 将完成大部分复杂的工作,开发人员只需关心获取和设置缓存。)

夏俊备注:我看了下ibatis缓存机制,内存区域的缓存和磁盘缓存,ibatis也有实现。

JCS 配置配置 JCS 就是简单地创建和填充一个 cache.ccf 文件。这个文件定义缓存应该使用哪些区域,以及这些区域的属性或选项。根据应用程序的需求配置这个文件是一种快速扩展缓存的简便方式。您可以指定许多适合配置的选项和属性来满足需求。

清单 1 显示的是最基本的 cache.ccf 文件 — 一个纯内存缓存配置:

清单 1. JCS 的基本配置

   

jcs.default=jcs.default.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes

jcs.default.cacheattributes.MaxObjects=1000

jcs.default.cacheattributes.MemoryCacheName=org.apache.jcs.engine.memory.lru.LRUMemoryCache

从清单 1 中可以看出,该配置文件将内存缓存指定为一个 LRUMemoryCache。还可以看到,内存中能保存的对象的最大数量被设置为 1000。

大多数应用程序的缓存系统配置要比清单 1 中复杂得多。在清单 2 的配置中,我在定义自己的区域(OUR_REGION)时使用了一个内存区域和一个磁盘区域:

清单 2. 在 JCS 配置中定义的区域

jcs.default=DISK_REGION

jcs.default.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes

jcs.default.cacheattributes.MaxObjects=1000

jcs.default.cacheattributes.MemoryCacheName=org.apache.jcs.engine.memory.lru.LRUMemoryCache

jcs.region.OUR_REGION=DISK_REGION

jcs.region.OUR_REGION.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes

jcs.region.OUR_REGION.cacheattributes.MaxObjects=1000

jcs.region.OUR_REGION.cacheattributes.MemoryCacheName=

  org.apache.jcs.engine.memory.lru.LRUMemoryCache

jcs.region.OUR_REGION.cacheattributes.UseMemoryShrinker=true

jcs.region.OUR_REGION.cacheattributes.MaxMemoryIdleTimeSeconds=3600

jcs.region.OUR_REGION.cacheattributes.ShrinkerIntervalSeconds=60

jcs.region.OUR_REGION.cacheattributes.MaxSpoolPerRun=500

jcs.region.OUR_REGION.elementattributes=org.apache.jcs.engine.ElementAttributes

jcs.region.OUR_REGION.elementattributes.IsEternal=false

jcs.auxiliary.DISK_REGION=org.apache.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory

jcs.auxiliary.DISK_REGION.attributes=

  org.apache.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes

jcs.auxiliary.DISK_REGION.attributes.DiskPath=c:/jcs/disk_region

jcs.auxiliary.DISK_REGION.attributes.maxKeySize=100000

清单 2 中的第一行表明该配置将默认区域设置为 DISK_REGION。DISK_REGION 是 IndexedDiskCacheFactory 类型,并且该文件在磁盘上指定为 c:\jcs\disk_region。清单 2 中的第二个配置组定义了我自己的区域,我为它添加了一些选项,这种类型的配置(在指定用户定义区域时同时使用内存区域和磁盘区域)是很常见的。清单 2 中的第 3 个配置组定义了一个 辅助区域。

JCS 有两个依赖项:concurrent 和 commons-logging(JCS 1.2.7.0 之前的版本中,还有两个其他依赖项:commons-collections 和 commons-lang)。

(JCS 辅助插件:除了 4 个核心缓存实现外,JCS 还提供了一些辅助插件,它们是区域可以使用的可选插件。这些辅助插件包括索引磁盘缓存(Indexed Disk Cache)、TCP 外围缓存(TCP Lateral Cache)和远程缓存服务器(Remote Cache Server)。例如,索引磁盘缓存允许在到达内存阈值时在磁盘上交换项目。这使得每个区域能更灵活地控制其缓存,提供一种类似于大多数操作系统所使用的虚拟内存的存储方法。cache.ccf 配置文件可以让每个辅助区域满足应用程序的需求。 )

JCS 的基本用法学习 JCS 基础知识的一个好方法是查看 API 最常用的方法。最好从初始化区域开始。初始化 JCS 缓存区域对象能使您访问大部分所需的常用方法。清单 3 初始化 JCS 对象并获得一个默认缓存区域实例:

清单 3. 检索默认缓存区域

// Initialize the JCS object and get an instance of the default cache region

JCS cache = JCS.getInstance("default");

检索 JCS 实例后,可以调用最需要的方法。put 方法将一个新对象放入缓存中。接下来只需一个 key(第一个参数)和一个 value(第二个参数)。清单 4 显示一个基本示例:

清单 4. 设置缓存项

                               

// Set up

String key = "key0";

String value = "value0";

// Place a new object in the cache

cache.put(key, value);

清单 4 中的示例使用字符串值作为参数,但是您可以使用任何对象。

检索缓存对象只不过是使用 JCS 提供的 get 方法。清单 5 显示了一个简单示例。同样,本例使用了一个字符串参数,但您可以使用任何对象。

清单 5. 检索缓存项

                               

// Retrieve a cached object

String cachedData = (String)cache.get(key);

测试缓存数据的有效性可能是处理缓存系统时需要使用的另一种方法。在 JCS 中,没有定义只测试缓存项是否存在的测试缓存方法。但是 get 方法的返回值可以帮助您。清单 6 显示了一种获得此必要功能的方式:

清单 6. 测试缓存项的有效性

                               

// Retrieve a cached object

String cachedData = (String)cache.get(key);

// Check if the retrieval worked

if (cachedData != null) {

  // The cachedData is valid and can be used

  System.out.println("Valid cached Data: " + cachedData);

}

最后需要几个用于在使用 JCS、缓存项和缓存区域后清除它们的常用缓存实用程序。JCS 提供了一种 clear 方法,用于从调用的缓存区域中删除所有缓存数据。此外,还提供了一个 remove 方法,用于删除指定缓存项。dispose 方法也可以处理初始化的 JCS 区域。清单 7 显示了如何使用这些方法:

清单 7. 清除缓存区域

                               

// Dispose of a specific cached item

cache.remove(key);

// Dispose of all cache data

cache.clear();

// Dispose of the cache region

cache.dispose();

JCS 和 Java 对象JCS 优于其他缓存系统(请参阅 参考资料)的一个地方是它可以很好地使用对象。大多数 Web 应用程序是使用面向对象的方法通过 Java 技术创建的。例如,与连续从数据库中逐段检索对象相比,缓存对象使应用程序能够更好地执行。

设计一个简单的面向对象的 JCS 站点的第一个步骤是创建需要存储的对象。在本例中,我将开发一个基本 blogging 站点。清单 8 显示了我将使用的 BlogObject 类:

清单 8. BlogObject

                               

package com.ibm.developerWorks.objects;

import java.io.Serializable;

import java.util.Date;

public class BlogObject implements Serializable {

  private static final long serialVersionUID = 6392376146163510046L;

  private int blogId;

  private String author;

  private Date date;

  private String title;

  private String content;

  public BlogObject(int blogId, String author, Date date, String title, String content) {

    this.blogId = blogId;

    this.author = author;

    this.date = date;

    this.title = title;

    this.content = content;

  }

  public int getBlogId() {

    return this.blogId;

  }

  public String getAuthor() {

    return this.author;

  }

  public Date getDate() {

    return this.date;

  }

  public String getTitle() {

    return this.title;

  }

  public String getContent() {

    return this.content;

  }

}

在一个类中表示对象后,接着还需要一个类来管理该对象。管理器处理所有与 blog 对象相关的管理和缓存功能。在本例中,管理器将处理三大任务:

·         检索 blog 对象

·         在缓存中设置 blog 对象

·         从缓存中清除 blog 对象

如清单 9 所示,getBlog 方法检索 blog 对象。该方法首先试图从缓存获得 blog 对象。如果该对象不在缓存中,它将根据其他机制获取该对象:

清单 9. 通过 blog 管理器检索 blog 对象

                               

public BlogObject getBlog(int id) {

  BlogObject blog = null;

  try {

    blogCache = JCS.getInstance(blogCacheRegion);

    blog = (BlogObject)blogCache.get(id);

  } catch (CacheException ce) {

    blog = null;

  }

  if (blog == null) {

    blog = DatabaseManager.getBlog(id);

    this.setBlog(

      blog.getBlogId(),

      blog.getAuthor(),

      blog.getDate(),

      blog.getTitle(),

      blog.getContent()

    );

  }

  return blog;

}

在清单 9 中,我使用一个数据库作为检索 blog 对象的替代机制。根据另一种机制检索该对象时,应该将该对象设置为缓存,以便下一次检索可以直接从该缓存获取这个对象。

如清单 10 所示,setBlog 方法将 blog 对象放在缓存中。这个方法比较简单,因为它只是使用传入的信息创建一个新的 blog 对象,然后将这个对象放在缓存中。

清单 10. 通过 blog 管理器将 blog 对象放在缓存中

public boolean setBlog(int bId, String author, Date date, String title, String content) {

  BlogObject blog = new BlogObject(bId, author, date, title, content);

  try {

    blogCache = JCS.getInstance(blogCacheRegion);

    blogCache.put(bId, blog);

    return true;

  } catch (CacheException ce) {

    return false;

  }

}

如清单 11 所示,cleanBlog 方法要么从缓存中清除一个指定的 blog,要么从缓存中清除掉所有 blog。这个方法使用 JCS 的 remove 和 clear 方法来清除缓存对象。

清单 11. 通过 blog 管理器从缓存中删除 blog 对象

                               

public boolean cleanBlog(int blogId) {

  try {

    blogCache = JCS.getInstance(blogCacheRegion);

    blogCache.remove(blogId);

  } catch (CacheException ce) {

    return false;

  }

  return true;

}

public boolean cleanBlog() {

  try {

    blogCache = JCS.getInstance(blogCacheRegion);

    blogCache.clear();

  } catch (CacheException ce) {

    return false;

  }

  return true;

}

前面的几个类展示了使用 JCS 缓存对象是很简单的。拥有对象管理器并使用简单的对象表示之后,您就获得一种在 Web 应用程序中处理对象的简单但强大的方法。

缓存元数据

JCS 提供了更多方法,向应用程序添加缓存所用的方法只是其中的一小部分。例如,它提供了收集缓存对象和缓存区域元数据的实用程序。您可以轻松检索以下内容:

·         缓存键名称

·         创建缓存项的时间

·         缓存可以存在的最长时间

·         缓存过期时间

清单 12 中的例子显示如何检索缓存项的元数据:

清单 12. 检索缓存项的元数据

                               

try {

  JCSAdminBean admin = new JCSAdminBean();

  LinkedList linkedList = admin.buildElementInfo(regionName);

  ListIterator iterator = linkedList.listIterator();

  while (iterator.hasNext()) {

    CacheElementInfo info = (CacheElementInfo)iterator.next();

    System.out.println("Key: " + info.getKey());

    System.out.println("Creation Time: " + info.getCreateTime());

    System.out.println("Maximum Life (seconds): " + info.getMaxLifeSeconds());

    System.out.println("Expires in (seconds): " + info.getExpiresInSeconds());

  }

} catch (Exception e) {

}

清单 13. 检索缓存区域的元数据

                               

try {

  JCSAdminBean admin = new JCSAdminBean();

  LinkedList linkedList = admin.buildCacheInfo();

  ListIterator iterator = linkedList.listIterator();

  while (iterator.hasNext()) {

    CacheRegionInfo info = (CacheRegionInfo)iterator.next();

    CompositeCache compCache = info.getCache();

    System.out.println("Cache Name: " + compCache.getCacheName());

    System.out.println("Cache Type: " + compCache.getCacheType());

    System.out.println("Cache Misses (not found): " + compCache.getMissCountNotFound());

    System.out.println("Cache Misses (expired): " + compCache.getMissCountExpired());

    System.out.println("Cache Hits (memory): " + compCache.getHitCountRam());

    System.out.println("Cache Updates: " + compCache.getUpdateCount());

  }

} catch (Exception e) {

}

收集缓存区域和项的元数据能帮助您分析 Web 站点的哪些区域和项目需要优化。元数据也能帮助您管理时间敏感型的缓存数据。例如,您可以使用每个缓存项的最长生命周期和过期时间来为需要更新数据的特定用户刷新缓存数据。

结束语JCS 是为 Java 开发人员提供的功能强大但简单易用的缓存系统。它为桌面和类似的 Web 应用程序提供数据缓存。类似桌面的 Web 应用程序的发展前景是提高速度和敏捷性。缓存数据对这些方面非常有益。本文概述如何配置和使用 JCS。此外,还讨论了基本缓存方法所需要语法,以及如何在常见 Web 应用程序中缓存对象和检索缓存元数据。解了 JCS 的基本知识之后,您现在可以利用数据缓存功能来开发下一个 Web 站点了。您还可以学习其他几个提供高级功能的 JCS 区域,比如 HTTP Servlet 访问、JCS 实用程序、基本 HTTP 验证和其他辅助区域。

b)     资料编号NO102

给WEB应用加JCS缓存系统:              

下载jcs-1.2.6.jar,找了半天也没有找到它的源码和API文档,不知为什么?
在这个站点有: Using JCS: Some basics for the web ,不错,就用它练习。

一、创建值对象

假设有一BOOK,它在数据库中的表为:
Table BOOK(BOOK_ID_PK ,TITLE , AUTHOR, ISBN, PRICE, PUBLISH_DATE)

创建值对象如下:

package com.genericbookstore.data;
import java.io.Serializable;
import java.util.Date;
public class BookVObj implements Serializable
{
    public int bookId = 0;
    public String title;
    public String author;
    public String ISBN; ..
    public String price;
    public Date publishDate;
    public BookVObj()
    {
    }
}

二、创建缓存管理器

应用中对book数据的访问都通过缓存管理器。

package com.genericbookstore.data;
import org.apache.jcs.JCS;
// in case we want to set some special behavior
import org.apache.jcs.engine.behavior.IElementAttributes;
public class BookVObjManager
{
    private static BookVObjManager instance;
    private static int checkedOut = 0;
    public static JCS bookCache;
    private BookVObjManager()//
构造函数
    {
        try
        {
            bookCache = JCS.getInstance("bookCache");
        }
        catch (Exception e)        {
            // Handle cache region initialization failure
        }
        // Do other initialization that may be necessary, such as getting
        // references to any data access classes we may need to populate
        // value objects later
    }
    /**
     * Singleton access point to the manager.
     */
    public static BookVObjManager getInstance()
    {
        synchronized (BookVObjManager.class)
        {
            if (instance == null)
            {

                  instance = new BookVObjManager();
            }
        }
        synchronized (instance)
        {
            instance.checkedOut++;
        }
        return instance;
    }
/**
     * Retrieves a BookVObj.  Default to look in the cache.
     */
    public BookVObj getBookVObj(int id)
    {
        return getBookVObj(id, true);
    }
    /**
     * Retrieves a BookVObj. Second argument decides whether to look
     * in the cache. Returns a new value object if one can't be ..
     * loaded from the database. Database cache synchronization is
     * handled by removing cache elements upon modification.
     */
    public BookVObj getBookVObj(int id, boolean fromCache)
    {
        BookVObj vObj = null;
        // First, if requested, attempt to load from cache
        if (fromCache)
        {
            vObj = (BookVObj) bookCache.get("BookVObj" + id);
        }
        // Either fromCache was false or the object was not found, so
        // call loadBookVObj to create it
        if (vObj == null)
        { ..
            vObj = loadBookVObj(id);
        }
        return  vObj;
    }
    /**
     * Creates a BookVObj based on the id of the BOOK table.  Data
     * access could be direct JDBC, some or mapping tool, or an EJB.
     */
    public BookVObj loadBookVObj(int id)
    {
        BookVObj vObj = new BookVObj();
        vObj.bookId = id;
        try
        {
            boolean found = false;
            // load the data and set the rest of the fields
            // set found to true if it was found

                  found = true;
            // cache the value object if found
            if (found)
            {
                // could use the defaults like this
                // bookCache.put( "BookVObj" + id, vObj );
                // or specify special characteristics
                // put to cache
                bookCache.put("BookVObj" + id, vObj);
            }
        }
        catch (Exception e)
        {

            // Handle failure putting object to cache
        }
        return vObj;
    }
    /**
     * Stores BookVObj's in database.  Clears old items and caches
     * new.
     */
    public void storeBookVObj(BookVObj vObj)
    {
        try
        {
            // since any cached data is no longer valid, we should
            // remove the item from the cache if it an update.
            if (vObj.bookId != 0)
            {
                bookCache.remove("BookVObj" + vObj.bookId);
            }
            // put the new object in the cache
            bookCache.put("BookVObj" + vObj.bookId, vObj);
        }
        catch (Exception e)
        {
            // Handle failure removing object or putting object to cache.
        }
    }
}

三、配置文件cache.ccf,它定义你配置何种类型的缓存、缓存的大小、过期时间等。

#WEB-INF/classes/cache.ccf(以下内容不要换行)
jcs.default=
jcs.default.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=1000

jcs.default.cacheattributes.MemoryCacheName=org.apache.jcs.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
jcs.default.cacheattributes.MaxSpoolPerRun=500
jcs.default.elementattributes=org.apache.jcs.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false

四、测试的JSP文件
<%@page import="com.genericbookstore.data.*,java.util.*" %>

<%

BookVObjManager cache = BookVObjManager.getInstance();


BookVObj bv1=cache.getBookVObj(8,true);

out.println(bv1.bookId);
%>


五、测试:http://127.0.0.1:8080/jcs/testjcs.jsp

c)      资料编号NO103

安装和配置:在web应用中安装和配置JCS是非常简单的事情。从Jakarta Turbine网站下载压缩文件,解压缩文件到临时目录,并拷贝JSC.jar文件(jcs-1.0-dev.jar)到servlet容器的通用目录(在我的web应用中使用的servlet容器是Tomcat,通用目录在windows下就是%TOMCAT_HOME%\common\lib,在再Unix类型的系统下就是$TOMCAT_HOME/common/lib)。你可能还需要commons-collections.jar, commons-lang.jar, 和 commons-logging.jar 这些文件存在于web应用的类路径下以便使用JCS。

框架的主要原理

缓存属性
  我们将所有的缓存参数配置在名为cache.ccf的属性文件中。这些参数包括缓存信息如:内存中存储的对象的最大数量,缓存时间(过了时间之后缓存的数据九自动从内存中释放),中断时间(elapsed time since last access time), 内存缓存名称(例如:缓存算法如LRU或MRU)等。在当前版本的JCS中,缓存属性文件是纯文本格式的。SpiritCache framework,一种来自SpiritSoft的Jcache API商业实现,支持XML格式的缓存配置。
  确认该属性文件存放在类路径中。注意:如果你需要使用其它不同的文件来存放缓存属性的话,JCS 也提供了方法来指定一个配置文件的名称。请参考JCS的 Javadocs 学习如何从其它非缺省的属性文件中读取缓存配置信息。
  下面列出来的是web应用使用缓存功能需要了解的一些Java类。这些类存放在本文的示例代码的common.caching包中。这些类的Javadocs也包括在源代码压缩包中。 (图2 中的类图显示了这些Java类的关系)
  ICacheManager
  这是客户应用实现所有缓存有关操作(如:存储、访问以及释放缓存中的数据)的主接口(契约)。客户程序可以是JSP、Struts Action类,或者就是一个POJO对象。创建该接口用于对客户端隐藏所有缓存的实现细节,这样当我们将来需要切换另一种的第三方缓存API的时候无需对客户端代码做任何调整。
  BaseCacheManager
  这是web门户缓存框架的主类。是对ICacheManager 接口的最基本实现。创建BaseCacheManager 用于在一个类中集中所有缓存相关的方法。它被设计为单例模式保证在servlet容器的JVM中有且仅有一个ICacheManager 的实例被创建。在多web服务器/servlet容器实例共同处理web请求的集群环境中,每个JVM将会创建独立的ICacheManager 实例。如果将来你要转换到不同的缓存API ,这是唯一需要为新的缓存API修改的类。如果你切换到JCache-兼容的缓存实现,对缓存管理器的修改将会是很小的。
  ICacheLoader
  该接口用于在web客户端实现真正的数据访问逻辑。所有需要使用缓存机制的客户端应用必须实现该接口。它包括仅有的一个方法叫做loadCacheObject() ,有两个输入参数:一个String参数制定缓存区域名称,一个对象参数制定缓存键值。这样,缓存管理器将知道在缓存的对象超过指定的“生存时间”的时候,使用哪个客户端程序(运行loadCacheObject 方法)来重载缓存中的对象 。
  ICacheKey
  ICacheKey 接口创建的目的是为了隐藏特定的创建缓存键值的细节。有时候缓存的键值不是一个简单的字符串。它可能像多个对象组合起来一样复杂,从数据源获取这些值需要多个查找方法而不是单一的方法。在这种情况下, ICacheKey 接口可以被用来定义创建缓存键值的所有复杂的逻辑。这样,缓存键值创建逻辑将会被定义为独立的类。我编写了一个简单的类TestCacheKey 实现了该接口并实现了getCacheKey() 方法来演示使用该接口的方法。
  CacheRegions
  一个 缓存区域 被定义为一个组织起来的命名空间用于容纳一组缓存对象集合。你需要在配置文件中定义缓存区域来实现在一块单独的内存空间中存储数据,管理缓存数据的有效期限。如果需要的话,对有相似特征的对象(例如:生存时间和业务用途)应该被缓存在相同的缓存区域中,让它们可以在相同的时间失效。我定义了分离的缓存区域来存储静态数据和小变动数据。为了避免同步操作带来的效率影响,我对每个缓存区域使用了单独的Cache (JCS) 实例。
  CacheElementInfo
  该类用于封装所有的缓存统计信息(例如:命中数、不中数、命中比例等),用来监测在web应用中所有缓存对象的效率。

编译, 构建, 和单元测试

我用Ant创建了一个构建脚本来编译我的对象缓存框架的所有代码。Ant的构建脚本build.xml, 放在WEB-INF\classes 目录下。我还编写了Junit测试客户端来测试使用web门户缓存框架的不同缓存场景。测试脚本CachingTestCase, 放在WEB-INF\classes\common\caching\test 目录下。解压缩示例代码到一个新的web应用目录,如果要验证Junit测试脚本,从命令行运行以下命令:

切换当前目录到%TOMCAT_HOME%/webapps/web-app-name/WEB-INF/classes (在Unix测试环境中,目录应该是$TOMCAT_HOME/webapps/web-app-name/WEB-INF/classes)。

运行以下命令:
  ant common.compile
  编译缓存框架中所有的Java类。
  ant common.runjunit
  用于运行Junit测试脚本。测试脚本使用Log4J API来显示所有的输出信息。
  考虑何时使用对象缓存的指导方针

当你决定要在你的web应用中缓存一些特定类别的数据的时候,请参照这些指导方针。缓存的应用应该经过谨慎地考虑,只有当其它方法,如:数据访问等,已经无法再进一步改进的时候才需要使用缓存。缓存将会带来复杂性,让维护工作变得更加复杂。因此,必须统筹考虑性能和缓存带来的复杂性的平衡关系。
  当考虑使用缓存的时候,需要考虑对象的预定执行时间和刷新率或者叫做对象的生存时间。缓存不能容纳所有我们想要存储的数据,因此缓存使用的内存及时得到释放,即可以通过定义合理的生存时间实现,也可以在数据不再需要的时候显式地释放被缓存的对象。可以指定缓存算法如最近被访问算法(LRU)或者最少被使用算法(LFU)以便缓存基于访问频率来释放对象。Jack Shirazi的著作 Java 性能调整 提供了一个关于缓存主题的非常有趣的讨论,讨论了什么类型的数据应该被缓存,以及何时使用缓存的建议。
  注意缓存框架并没有处理在web应用中需要被缓存的对象的创建(例如:从数据源检索数据的数据访问逻辑并没有在缓存类中编写)。这要依赖于客户程序来定义真正的数据访问逻辑。像Java数据对象等技术通常用于在企业级web应用中封装数据访问逻辑。参考O'Reilly的 Java 数据对象 来学习更多的关于如何将数据访问层与业务逻辑层分离的知识。
  结论
  本文提供了对使用Jakarta的Java缓存系统(JCS)来为web门户应用开发对象缓存框架的概要介绍。该框架非常稳定并可以被重用于其它任何web应用,甚至可以用于客户/服务器模式的Java应用程序。本文详细介绍了web门户缓存框架的工作原理,并提供了Junit测试脚本来对不同场景的缓存框架进行测试。
  JCS was built as a system close to JCACHE Java Temporary Caching API (JSR-107), a description of the caching system used in Oracle 9i and other popular caching frameworks. 该规范可能会在将来的JDK发行版本中作为一种Java扩展框架。我的其中一个目的就是让web门户缓存框架与JCS保持松散耦合。这样的话,如果我将来需要转换到另一种框架(例如Jcache),我可以在对web门户应用客户程序代码不做大的调整的情况下完成切换。
  我现在通过记录缓存监测信息的日志(使用Log4J API)如:命中数、不中数、命中率来衡量缓存的效率。可能将来有其它参数需要被监测来衡量缓存的效率。同样的,用来测量使用或不使用缓存对数据访问的反馈时间,应该使用一些负载测试工具如:Grinder或者Jmeter来测试其伸缩性和性能效果。
  在机群环境下保持缓存同步将是一个挑战,因为每个servlet容器将会在自己的JVM中拥有一个缓存管理器实例。解决该问题的方法就是创建消息驱动Bean(MDB)在需要刷新数据的时候通知所有的缓存管理器。
  通常的对象查找方法,如:简单的Hashtable、JNDI甚至是EJB,提供了在内存中存放对象并通过键值查找对象的方法。但是任何一种方法都没有提供当对象不需要的时候从内存中移出的机制,或者当访问对象迟于对象存放期限的时候自动创建对象的机制。HttpSession 对象 (in the servlet package) 也允许对象被缓存,但是它没有共享、失效、单一对象存放期满、自动装载或者spooling 这些缓存框架需要具备的基础机制。
  虽然将缓存功能集成到web应用中需要额外的设计和开发工作,但我认为缓存带来的利益大于额外付出的工作。我已经看到在我实现了缓存框架之后 ,我的web应用的性能有很大的提高,特别是在访问静态数据和查找结果方面。该web应用模块目前处于测试阶段。在不久的将来,我会提供一些性能方面的测试数据(包括使用与不使用缓存的情况)来比较缓存如何帮助设计更快、更具伸缩性的web应用。

图1

图2

d)     资料编号NO104

    JCS是Jakarta的项目Turbine的子项目。它是一个复合式的缓冲工具。可以将对象缓冲到内存、硬盘。具有缓冲对象时间过期设定。还可以通过JCS构建具有缓冲的分布式构架,以实现高性能的应用。
    对于一些需要频繁访问而每访问一次都非常消耗资源的对象,可以临时存放在缓冲区中,这样可以提高服务的性能。而JCS正是一个很好的缓冲工具。缓冲工具对于读操作远远多于写操作的应用性能提高非常显著。
    JCS的详细说明在 http://jakarta.apache.org/turbine/jcs/
    我想使用到它是因为我想实现一个有时效性的对象的东西,当一个对象一段时间不操作,则销毁!

  示例代码:
缓存的对象User,一定要实现Serializable接口

package org.c2one.sercenter.entity;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

public class User implements Serializable {

private String name;

private String password;

private Map<String, Object> detailInfoMap = new HashMap<String, Object>();

public Map<String, Object> getDetailInfoMap() {
   return detailInfoMap;
}

public void setDetailInfoMap(Map<String, Object> detailInfoMap) {
   this.detailInfoMap = detailInfoMap;
}

public String getName() {
   return name;
}

public void setName(String name) {
   this.name = name;
}

public String getPassword() {
   return password;
}

public void setPassword(String password) {
   this.password = password;
}
}

缓存操作类 UserManager

package org.c2one.sercenter.cache;

import org.apache.jcs.JCS;
import org.apache.jcs.access.exception.CacheException;
import org.apache.log4j.Logger;
import org.c2one.sercenter.entity.User;
import org.c2one.sercenter.service.UserServiceImpl;

public class UserManager {

private static final Logger logger = Logger.getLogger(UserManager.class);

private JCS jcs;

private static UserManager userCache;

public static UserManager getInstance() throws CacheException {
   if (userCache == null) {
    userCache = new UserManager();
   //
使用default的jcs配置
    userCache.jcs = JCS.getInstance("userCache");
   }
   return userCache;
}

public void regiestUser(String key, User user) throws CacheException {
   jcs.put(key, user);
}

public User getUser(String key) {
   return (User) jcs.get(key);
}
}

另外需要的就剩下jcs的配置文件cache.ccf,放到src的根目录下就行
内存上的LRU缓存机制配置:

# DEFAULT CACHE REGION

# sets the default aux value for any non configured caches
jcs.default=
jcs.default.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes
#
存放对象个数
jcs.default.cacheattributes.MaxObjects=1000
jcs.default.cacheattributes.MemoryCacheName=org.apache.jcs.engine.memory.lru.LRUMemoryCache
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLifeSeconds=3600
jcs.default.elementattributes.IdleTime=1800
jcs.default.elementattributes.IsSpool=true
jcs.default.elementattributes.IsRemote=true
jcs.default.elementattributes.IsLateral=true
#这里指明对象超过3600秒则过期,每隔60秒检查一次
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60

(二)  第二份资料—OSCache

e)      资料编号NO201

一、   缓存整个页面

在OSCache组件中提供了一个CacheFilter用于实现页面级的缓存,主要用于对web应用中的某些动态页面进行缓存,尤其是那些需要生成PDF格式文件/报表、图片文件等的页面,不仅减少了数据库的交互、减少数据库服务器的压力,而且对于减少web服务器的性能消耗有很显著的效果。

这种功能的实现是通过在web.xml中进行配置来决定缓存哪一个或者一组页面,而且还可以设置缓存的相关属性,这种基于配置文件的实现方式对于J2EE来说应该是一种标准的实现方式了。

[注] 只有客户访问时返回http头信息中代码为200(也就是访问已经成功)的页面信息才能够被缓存。

修改web.xml,增加如下内容,确定对/testContent.jsp页面进行缓存。

<filter>

      <filter-name>CacheFilter</filter-name>

         <filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>

         <init-param>

            <param-name>time</param-name>

            <param-value>600</param-value>

          </init-param>

          <init-param>

           <param-name>scope</param-name>

           <param-value>session</param-value>

          </init-param>

</filter>

<filter-mapping>

<filter-name>CacheFilter</filter-name>

<!-对所有jsp页面内容进行缓存-->

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

</filter-mapping>

在页面级缓存的情况下,可以通过设置CacheFilter的初始属性来决定缓存的一些特性:time属性设置缓存的时间段,默认为3600秒,可以根据自己的需要只有的设置,而scope属性设置,默认为application,可选项包括application、session。

二、   缓存页面的部分

1、  OSCache标签库配置
(1) 从src\webapp\WEB-INF\classes或etc目录取得soscache.tld文件,放在CLASSPATH下(src根目录或发布环境的/WEB-INF/classes  目录)。该文件定义了OSCache的定义。
(2) 将下列代码加入web.xml文件中:

<taglib>
<taglib-uri>oscache</taglib-uri>
<taglib-location>/WEB-INF/classes/oscache.tld</taglib-location>
</taglib>

2、  cache标签

        这是OSCache提供的标签库中最重要的一个标签,包括在标签中的内容将应用缓存机制进行处理,处理的方式将取决于编程者对cache标签属性的设置。
        第一次请求到达时,标签中的内容被处理并且缓存起来,当下一个请求到达时,缓存系统会检查这部分内容的缓存是否已经失效,主要是以下几项:
        (1)缓存时间超过了cache标签设置的time或者duration属性规定的超时时间
        (2)cron属性规定的时间比缓存信息的开始时间更晚
        (3)标签中缓存的内容在缓存后又被重新刷新过
        (4)其他缓存超期设定
        如果符合上面四项中的任何一项,被缓存的内容视为已经失效,这时被缓存的内容将被重新处理并且返回处理过后的信息,如果被缓存的内容没有失效,那么返回给用户的将是缓存中的信息。
        cache标签的常用属性说明:

这些属性可以单独使用,也可以根据需要组合使用。

3、Cron表达式基本语法
        通过Cron表达式我们可以很灵活的设置缓存的失效时间,Cron表达式包括5个字段分别为Minute,Hour, DOM(Day Of Month), Month,DOW(Day Of Week)。他们顺序地对应了5个位置。当某个位置上的值为*时,表示该位置上的任意时间。另外还提供了指定时间的操作符号"-",",","/",他们分别表示一段时间范围,具体的时间,以及递增的时间段。下面是几个例子说明一下Cron表达式的基本应用: 
        (1) "10/20 * * * *" :因是第一个位置,并且是一个递增的表达式,所以表达式指定的是每个小时的第10分钟,第30分钟,第50分钟缓存内容失效。
        (2) "* 8-18/4 * * *" :指定每天早上8点到晚上6点之间,每4个小时缓存内容失效。  等同于"* 8,12,16 * * *"。
        (3) "* * * * 1-5":表示每个星期一到星期五内容失效。

4、Cache标签实例分析

(1) 最简单的cache标签用法。使用默认的关键字来标识cache内容,超时时间是默认的3600秒。

<oscache:cache>
<%
//
自己的JSP代码内容
%>
</oscache:cache>

(2) 用自己指定的字符串标识缓存内容,并且设定作用范围为session。

<oscache:cache key="foobar" scope="session">
<%
//
自己的JSP代码内容
%>
</oscache:cache>

(3) 动态设定key值,使用自己指定的time属性设定缓存内容的超时时间,使用动态refresh值决定是否强制内容刷新。因为OSCache使用key值来标识缓存内容,使用相同的key值将会被认为使用相同的的缓存内容,所以使用动态的key值可以自由的根据不同的角色、不同的要求决定使用不同的缓存内容。

<oscache:cache key="<%= product.getId() %>" time="1800" refresh="<%= needRefresh %>">
<%
//
自己的JSP代码内容
%>
</oscache:cache>

(4) 设置time属性为负数使缓存内容永不过期

<oscache:cache time="-1">
<%
//
自己的JSP代码内容
%>
</oscache:cache>

(5) 使用duration属性设置超期时间

<oscache:cache  duration='PT5M'>
<%
//
自己的JSP代码内容
%>
</oscache:cache>

(6) 使用mode属性使被缓存的内容不加入给客户的响应中

<oscache:cache  mode='silent'>
<%
//
自己的JSP代码内容
%>
</oscache:cache>

5、flush标签

        这个标签用于在运行时刷新缓存。只有运行flush标签后再次访问相关缓存项时才执行刷新。
        属性说明:

      

6、usecached标签
        <usecached />:必须嵌套在<cache>标签中。
        属性说明:

示例代码如下:

<oscache:cache>
     <% try { %>
     ... some jsp content ...
     <% } catch (Exception e) { %>
          <cache:usecached />
     <% } %>
</oscache:cache>

7、addgroup标签

        <addgroup />:必须嵌套在<cache>标签中。It allows groups to be dynamically added to a cached block. It is useful when the group(s) a cached block should belong to are unknown until the block is actually rendered. As each group is 'discovered', this tag can be used to add the group to the block's group list.
        属性说明:

示例代码如下:

<oscache:cache key="test1">

<oscache:addgroup group="group1" />

... some jsp content ...

<oscache:addgroup group="group2" />

... some more jsp content ...

</oscache:cache>

8、使用标签的特殊说明

   (1) 标签的属性值如果动态生成,则需要先把动态生成的值赋予一个变量,再使用JSP 表达式把动态值赋予对应的属性。

<!--正确的写法:-->

<%

String keyValue = (String)request.getAttribute("keyValue");

if(keyValue == null)

keyValue = "";

%>

<oscache:cache  refresh='<%=keyValue%>'>……</ oscache:cache >

<!--不正确的写法:-->

<oscache:cache  refresh='<%=(String)request.getAttribute("keyValue")%>'>

<!-属性的值此时为字符串“<%=(String)request.getAttribute("keyValue")%>”--->

</ oscache:cache >

(2) 标签的属性值对boolean是强类型的,比如cache的refresh属性要求为true或false,示例如下:

<!--正确的写法:-->

<oscache:cache  refresh='true'>……</ oscache:cache >

<!--正确的写法:-->

<%

String needRefresh = (String)application.getAttribute("needRefresh");

if(needRefresh == null)

needRefresh = "false";

boolean t_f = Boolean.valueOf(needRefresh).booleanValue();

%>

<oscache:cache  refresh='<%=t_f %>'>……</ oscache:cache >

<!--不正确的写法:-->

<oscache:cache  refresh='<%= needRefresh %>'>……</ oscache:cache >

f)       资料编号NO202

OSCache是当前运用最广的缓存方案,JBoss,Hibernate,Spring等都对其有支持,下面简单介绍一下OSCache的配置和使用过程。

安装过程

·从http://www.opensymphony.com/oscache/download.html下载合适的OSCache版本,我下载的是oscache-2.0.2-full版本。

·解压缩下载的文件到指定目录,从解压缩目录取得oscache.jar文件放到/WEB-INF/lib或相应类库目录中,jar文件名可能含有版本号和该版本的发布日期信息等,如oscache-2.0.2-22Jan04.jar。

·如果你的jdk版本为1.3.x,建议在lib中加入Apache Common Lib 的commons-collections.jar包,如jdk是1.4以上则不必。

·从src或etc目录取得oscache.properties 文件,放入src根目录或发布环境的/WEB-INF/classes 目录,如你需要建立磁盘缓存,须修改oscache.properties 中的cache.path信息。win类路径类似为c:\app\cache,unix类路径类似为/opt/myapp/cache。

·拷贝OSCache标签库文件oscache.tld到/WEB-INF/classes目录。

·现在你的应用目录类似如下:

$WEB_APPLICATIONWEB-INFliboscache.jar

$WEB_APPLICATIONWEB-INFclassesoscache.properties

$WEB_APPLICATIONWEB-INFclassesoscache.tld

·将下列代码加入web.xml文件中

<taglib>

<taglib-uri>oscache</taglib-uri>

<taglib-location>/WEB-INF/classes/oscache.tld</taglib-location>

</taglib>

·为了便于调试日志输出,须加入commons-logging.jar和log4j-1.2.8.jar到当前类库路径中,在src目录加入下面两个日志输出配置文件:

log4j.properties 文件内容为:

log4j.rootLogger=DEBUG,stdout,file

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern=[start]%d{yyyy/MM/dd/ HH:mm:ss}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD] n%c[CATEGORY]%n%m[MESSAGE]%n%n

log4j.appender.file=org.apache.log4j.RollingFileAppender

log4j.appender.file.File=oscache.log

log4j.appender.file.MaxFileSize=100KB

log4j.appender.file.MaxBackupIndex=5

log4j.appender.file.layout=org.apache.log4j.PatternLayout

log4j.appender.file.layout.ConversionPattern=[start]%d{yyyy/MM/dd/ HH:mm:ss}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD] n%c[CATEGORY]%n%m[MESSAGE]%n%n

log4j.logger.org.apache.commons=ERROR

log4j.logger.com.opensymphony.oscache.base=INFO

commons-logging.properties文件内容为:

org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JCategoryLog

oscache.properties文件配置向导

cache.memory:值为true或false,默认为在内存中作缓存,如设置为false,那cache只能缓存到数据库或硬盘中,那cache还有什么意义。

cache.capacity:缓存元素个数。

cache.persistence.class:持久化缓存类,如此类打开,则必须设置cache.path信息。

cache.cluster相关:为集群设置信息。

例如:

cache.cluster.multicast.ip为广播IP地址

cache.cluster.properties为集群属性

OSCache的基本用法

cache1.jsp内容如下

<%@ page import="java.util.*" %>

<%@ taglib uri="oscache" prefix="cache" %>

<html>

<body>

没有缓存的日期: <%= new Date() %><p>

<!--自动刷新-->

<cache:cache time="30">

每30秒刷新缓存一次的日期: <%= new Date() %>

</cache:cache>

<!--手动刷新-->

<cache:cache key="testcache">

手动刷新缓存的日期: <%= new Date() %> <p>

</cache:cache>

<a href="cache2.jsp">手动刷新</a>

</body>

</html>

cache2.jsp执行手动刷新页面如下

< %@ taglib uri="oscache" prefix="cache" % >

<html>

<body>

缓存已刷新...<p>

<cache:flush key="testcache" scope="application"/>

<a href="cache1.jsp">返回</a>

</body>

</html>

你也可以通过下面语句定义Cache的有效范围,如不定义scope,scope默认为Applcation程序代码:

<cache:cache time="30" scope="session">

...

</cache:cache>

缓存过滤器CacheFilter

你可以在web.xml中定义缓存过滤器,定义特定资源的缓存。

<filter>

<filter-name>CacheFilter</filter-name>

<filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>

<init-param>

<param-name>time</param-name>

<param-value>60</param-value>

</init-param>

<init-param>

<param-name>scope</param-name>

<param-value>session</param-value>

</init-param>

</filter>

<filter-mapping>

<filter-name>CacheFilter</filter-name>

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

</filter-mapping>

上面定义将缓存所有.jsp页面,缓存刷新时间为60秒,缓存作用域为Session。

注意:CacheFilter只捕获Http头为200的页面请求,即只对无错误请求作缓存,而不对其他请求(如500,404,400)作缓存处理。

g)     资料编号NO203

应用oscache提升j2ee系统运行性能:Cache是一种用于提高系统响应速度、改善系统运行性能的技术。尤其是在Web应用中,通过缓存页面的输出结果,可以很显著的改善系统运行性能。本文中作者给大家介绍一个实现J2EE框架中Web应用层缓存功能的开放源代码项目----OSCache。通过应用OSCache,我们不但可以实现通常的Cache功能,还能够改善系统的稳定性。

1 面临的问题

1.1 需要处理的特殊动态内容

在信息系统建设过程中我们通常会遇到这样的问题:

1. 基础数据的变更问题

信息系统中需要处理的基础数据的内容短时间内是不会发生变化的,但是在一个相对长一些的时间里,它却可能是动态增加或者减少的。

举个例子:电子商务中关于送货区域的定义,可能短时间内不会发生变化,但是随着电子商务企业业务的扩大,系统中需要处理的送货区域就可能增加。所以我们的系统中不得不在每次向客户展示送货区域信息的时候都和数据库(假设送货区域信息保存在数据库中,这也是通常采用的处理方法)进行交互。

2. 统计报表(不仅限于统计报表)的问题

一般来说,统计报表是一个周期性的工作,可能是半个月、一个月或者更长的时间才会需要更新一次,然而统计报表通常是图形显示或者是生成pdf、word、excel等格式的文件,这些图形内容、文件的生成通常需要消耗很多的系统资源,给系统运行造成很大的负担。

1.2 问题的共同点

通过比较分析,不难发现这两类问题有一些共同点:

1、被处理的内容短时间不变,所以短时间内可以作为静态内容进行处理

2、在一个不太长的时间内,被处理的内容可能或者必定产生变化,所以必须将他们作为动态内容进行处理

3、在合理的时间区段内可以忽略被处理内容变化后带来的影响

4、对这些内容的处理动作比较消耗系统性能,影响系统响应时间

1.3 解决方法

缓存技术可以帮助我们很好的解决这个问题:

1、缓存信息

当上述的基础数据或者统计报表第一次被访问时,被处理的内容被当作动态信息,基础数库从数据库中获得,统计报表也会被生成符合要求的图形、文件,然后这些信息都会被放入缓存信息中。

2、响应信息由缓存提供

当上述的基础数据或者统计报表继续被访问时,系统将会首先检查缓存信息中是否有对应的内容和我们设定的缓存规则,如果符合缓存信息存在而且符合缓存规则,给出的响应将来自于缓存信息,如果没有或者缓存信息已经不符合设定的要求,系统将重复上一步的动作。

很显然,上面的步骤2中,多数情况下,当用户请求到达时,被处理的内容将来自于缓存,所以大大的减少了与数据库的交互,或者不再需要为每个请求都生成一次报表图形或者文件,这部分工作的减少对于降低系统性能消耗、提高系统稳定性和并发处理能力是非常有益的。

2 OSCache简介

OSCache是OpenSymphony组织提供的一个J2EE架构中Web应用层的缓存技术实现组件,它的出现解决了我们面临的问题。 OSCache目前最新的稳定版本是2.0,本文中的例子都是基于这个版本的,如果大家运行例子的过程中发生问题,请首先确认是否采用了正确的软件版本。

2.1 主要特征

1. 兼容多种支持JSP的web服务器

已经通过兼容测试的web服务器包括OrionServer (1.4.0或者以上版本) 、Macromedia JRun (3.0或者以上版本) 、BEA Weblogic (7.x或者以上版本) 、IBM Websphere (5.0版本)、Silverstream (3.7.4版本)、Caucho Resin (1.2.3或者以上版本)、Tomcat (4.0或者以上版本) ,其他支持servlet2.3、jsp1.2的web服务器应该都是完全兼容OSCache的。

2. 可选的缓存区

你可以使用内存、硬盘空间、同时使用内存和硬盘或者提供自己的其他资源(需要自己提供适配器)作为缓存区。

使用内存作为缓存区将可以提供更好的性能

使用硬盘作为缓存区可以在服务器重起后迅速恢复缓存内容

同时使用内存和硬盘作为缓存区则可以减少对内存的占用

3. 灵活的缓存系统

OSCache支持对部分页面内容或者对页面级的响应内容进行缓存,编程者可以根据不同的需求、不同的环境选择不同的缓存级别。

4. 容错

在一般的web应用中,如果某个页面需要和数据库打交道,而当客户请求到达时,web应用和数据库之间无法进行交互,那么将返回给用户"系统出错"或者类似的提示信息,如果使用了OSCache的话,你可以使用缓存提供给用户,给自己赢得维护系统或者采取其他补救的时间。

其它特性还包括对集群的支持、缓存主动刷新等特性,大家可以参考OpenSymphony网站上的其他资源获取更多的信息。

3 OSCache组件的安装

OSCache是一个基于web应用的组件,他的安装工作主要是对web应用进行配置,大概的步骤如下:

1. 下载、解压缩OSCache

请到OSCache的主页http://www.opensymphony.com/oscache/download.html下载Oscache的最新版本,作者下载的是OSCache的最新稳定版本2.0。

将下载后的。Zip文件解压缩到c:\oscache(后面的章节中将使用%OSCache_Home%来表示这个目录)目录下

2. 新建立一个web应用

3. 将主要组件%OSCache_Home%\oscache.jar放入WEB-INF\lib目录

4. commons-logging.jar、commons-collections.jar的处理

OSCache组件用Jakarta Commons Logging来处理日志信息,所以需要commons-logging.jar的支持,请将%OSCache_Home%\lib\core\commons-logging.jar放入classpath(通常意味着将这个文件放入WEB-INF\lib目录)

如果使用JDK1.3,请将%OSCache_Home%\lib\core\commons-collections.jar放入classpath,如果使用JDK1.4或者以上版本,则不需要了

5. 将oscache.properties、oscache.tld放入WEB-INF\class目录

%OSCache_Home%\oscache.properties包含了对OSCache运行特征值的设置信息

%OSCache_Home%\oscache.tld包含了OSCache提供的标签库的定义内容

6. 修改web.xml文件

在web.xml文件中增加下面的内容,增加对OSCache提供的taglib的支持:

<taglib>

<taglib-uri>oscache</taglib-uri>

<taglib-location>/WEB-INF/classes/ oscache.tld</taglib-location>

</taglib>

4 开始使用OSCache中的缓存组件

OSCache中按照缓存范围的不同分为两种不同的方式:一种是缓存JSP页面中部分或者全部内容,一种是基于整个页面文件的缓存。

4.1 JSP部分内容缓存

4.1.1 Cache-OSCache提供的缓存标签

这是OSCache提供的标签库中最重要的一个标签,包括在标签中的内容将应用缓存机制进行处理,处理的方式将取决于编程者对cache标签属性的设置。

第一次请求到达时,标签中的内容被处理并且缓存起来,当下一个请求到达时,缓存系统会检查这部分内容的缓存是否已经失效,主要是以下几项:

1. 缓存时间超过了cache标签设置的time或者duration属性规定的超时时间

2. cron属性规定的时间比缓存信息的开始时间更晚

3. 标签中缓存的内容在缓存后又被重新刷新过

4. 其他缓存超期设定

如果符合上面四项中的任何一项,被缓存的内容视为已经失效,这时被缓存的内容将被重新处理并且返回处理过后的信息,如果被缓存的内容没有失效,那么返回给用户的将是缓存中的信息。

cache标签的属性说明:

key - 标识缓存内容的关键词。在指定的作用范围内必须是唯一的。默认的key是被访问页面的URI和后面的请求字符串。

你可以在同一个页面中使用很多cache标签而不指定他的key属性,这种情况下系统使用该页面的URI和后面的请求字符串,另外再自动给这些key增加一个索引值来区分这些缓存内容。但是不推荐采用这样的方式。

scope - 缓存发生作用的范围,可以是application或者session

time - 缓存内容的时间段,单位是秒,默认是3600秒,也就是一个小时,如果设定一个负值,那么这部分被缓存的内容将永远不过期。

duration - 指定缓存内容失效的时间,是相对time的另一个选择,可以使用简单日期格式或者符合USO-8601的日期格式。如:duration='PT5M' duration='5s'等

refresh - false 或者true。

如果refresh属性设置为true,不管其他的属性是否符合条件,这部分被缓存的内容都将被更新,这给编程者一种选择,决定什么时候必须刷新。

mode - 如果编程者不希望被缓存的内容增加到给用户的响应中,可以设置mode属性为"silent"

其它可用的属性还包括:cron 、groups、language、refreshpolicyclass、refreshpolicyparam。

上面的这些属性可以单独使用,也可以根据需要组合使用,下面的例子将讲解这些常用属性的使用方式。

4.1.2 Cache标签实例分析:

1. 最简单的cache标签用法

使用默认的关键字来标识cache内容,超时时间是默认的3600秒

<cache:cache>

<%

//自己的JSP代码内容

%>

</cache:cache>

2. 用自己指定的字符串标识缓存内容,并且设定作用范围为session。

<cache:cache key="foobar" scope="session">

<%

//自己的JSP代码内容

%>

</cache:cache>

3.动态设定key值,使用自己指定的time属性设定缓存内容的超时时间,使用动态refresh值决定是否强制内容刷新。

因为OSCache使用key值来标识缓存内容,使用相同的key值将会被认为使用相同的的缓存内容,所以使用动态的key值可以自由的根据不同的角色、不同的要求决定使用不同的缓存内容。

<cache:cache key="<%= product.getId() %>" time="1800" refresh="<%= needRefresh %>">

<%

//自己的JSP代码内容

%>

</cache:cache>

4. 设置time属性为负数使缓存内容永不过期

<cache:cache time="-1">

<%

//自己的JSP代码内容

%>

5. 使用duration属性设置超期时间

<cache:cache  duration='PT5M'>

<%

//自己的JSP代码内容

%>

6. 使用mode属性使被缓存的内容不加入给客户的响应中

<cache:cache  mode='silent'>

<%

//自己的JSP代码内容

%>

4.2 用CashFilter实现页面级缓存

在OSCache组件中提供了一个CacheFilter用于实现页面级的缓存,主要用于对web应用中的某些动态页面进行缓存,尤其是那些需要生成pdf格式文件/报表、图片文件等的页面,不仅减少了数据库的交互、减少数据库服务器的压力,而且对于减少web服务器的性能消耗有很显著的效果。

这种功能的实现是通过在web.xml中进行配置来决定缓存哪一个或者一组页面,而且还可以设置缓存的相关属性,这种基于配置文件的实现方式对于J2EE来说应该是一种标准的实现方式了。

[注] 只有客户访问时返回http头信息中代码为200(也就是访问已经成功)的页面信息才能够被缓存

1. 缓存单个文件

修改web.xml,增加如下内容,确定对/testContent.jsp页面进行缓存。

<filter>

      <filter-name>CacheFilter</filter-name>

<filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>CacheFilter</filter-name>

<!-对/testContent.jsp页面内容进行缓存-->

      <url-pattern>/testContent.jsp</url-pattern>

</filter-mapping>

2. 缓存URL pattern

修改web.xml,增加如下内容,确定对*.jsp页面进行缓存。

<filter>

      <filter-name>CacheFilter</filter-name>

<filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>CacheFilter</filter-name>

<!-对所有jsp页面内容进行缓存-->

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

</filter-mapping>

3. 自己设定缓存属性

在页面级缓存的情况下,可以通过设置CacheFilter的初始属性来决定缓存的一些特性:time属性设置缓存的时间段,默认为3600秒,可以根据自己的需要只有的设置,而scope属性设置,默认为application,可选项包括application、session

<filter>

      <filter-name>CacheFilter</filter-name>

<filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>

    <init-param>

         <param-name>time</param-name>

         <param-value>600</param-value>

      </init-param>

      <init-param>

         <param-name>scope</param-name>

         <param-value>session</param-value>

      </init-param>

</filter>

<filter-mapping>

<filter-name>CacheFilter</filter-name>

<!-对所有jsp页面内容进行缓存-->

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

</filter-mapping>

5 性能测试结果

5.1 测试环境

系统平台:windows 20## 高级服务器/ P3 800 /512M内存

web服务器:websphere 5.0

数据库服务器:mysql 4.0.18-nt

性能测试用工具:apache Jmeter

5.2 测试计划

这次性能测试对比方为使用缓存和不使用缓存两种,他们的访问代码都是一样的:通过数据源从本地mysql数据库中获取person表的所有记录,然后显示在页面上。

测试中将模仿10个用户,每个用户发起5次请求,然后统计所有访问花费的时间。

5.3 测试结果

使用缓存后的测试结果 不使用缓存时的测试结果

所有请求花费的总时间(毫秒) 20569 22870

性能测试的详细结果请大家查看下载内容中的《不使用cache时的系统性能测试结果.txt》和《使用cache后系统性能测试结果.txt》

6 总结

在J2EE系统中,我们经常需要处理一些特殊的动态内容,这些内容在一个时间段内的变更非常有限,但是又不得不将他们确定为动态内容进行输出,而且非常消耗数据库系统资源或者web服务器的资源,这时我们就可以采用Cache----一种用于提高系统响应速度、改善系统运行性能的技术----来优化我们的系统。尤其是在Web应用中,这种处理可以很显著的改善系统运行性能。

本文中作者给大家介绍一个实现J2EE框架中Web应用层缓存功能的开放源代码项目----OSCache。它提供了在J2EE系统中实现缓存需要的丰富的功能。通过应用OSCache,我们不但可以实现通常的Cache功能、自由的设定cache的相关特性比如缓存时间段/缓存内容等,提升系统性能,而且还能有效的改善系统的稳定性。除此之外,OSCache组件还提供了更多的特性比如集群、容错、灵活的缓存区选择等。

作者根据自己的使用经验给大家提供了一些简单的例子,他们部分演示了如何使用OSCache组件提供的丰富特性,OSCache提供的特性远不止这些,需要大家在今后的时间里深入的研究,同时也希望大家通过E-mail和作者贡献研究成果。

h)     资料编号NO204

OSCache文档-3.3在集群系统中使用OSCache

OSCache 2.0有个新特性是对集群缓存的支持.OSCache当前是搭载实现的,它允许你使用JavaGroups或JMS作为底层的广播协议.

跨集群机缓存仅在数据涌流发生事件发生时才广播消息。也就是是说,服务器缓存内容是相互独立的,但是无论何时一台服务器中内容成旧后,其它的也会认为是成旧的。因为我们不必将缓存的对象传到周边的集群机,所以它提供给我们一个很好的解决方案,再加上在集群系统中没有中心机来控制集群系统,故及群系统的鲁棒性非常好。

对一个集群系统配置OSCache非常简单。根据你选择的协议(JavaGroups或JMS)按照下面对应的操作进行即可完成配置.

JMS的配置

配置你的JMS服务器.OSCache需要一个JMS连接工厂和一个通过JNDI可以获得的主题.详情请参阅JMS服务器文档.

按照下面的格式将JMS广播协议监听器添加到你的oscache.properties :

cache.event.listeners=com.opensymphony.oscache.plugins.clustersupport.JMSBroadcastingListener

(注意: JMS广播协议监听器要求JMS 1.1 或更高版本,然而,附带的也提供支持1.0.x的。如果你的JMS服务器仅支持JMS1.0.x,那请使用JMS1.0待替JMS广播协议监听器.其它的文档也适用于1.1和1.0版监听器)

The JMS listener supports the following configuration parameters:

JMS监听器支持下面配置参数:

cache.cluster.jms.topic.factory - 邦定JMS主题连接工厂的JNDI名。这个应该和你JMS服务器中相匹配.典型的,它是这样的格式: "java:comp/env/jms/TopicConnectionFactory".

cache.cluster.jms.topic.name - 用来让OSCache发送消息的JNDI名.这个应该和你JMS服务器中配置的名字相匹配.典型的格式为:"java:comp/env/jms/OSCacheTopic".

cache.cluster.jms.node.name - 在集群机中一个唯一标识一个节点的名字.它用来防止节点处理自己的广播消息。每一个集群系统中的节点有一个不同的值,例如"node1","node2",....

如果你孤立的通过一个程序运行OSCache或没有InitialContext()可以发现你的JNDI InitialContextFactory 或提供者url的环境中时,你将必须在jndi.properties文件或者系统属性中来特别的设置它们。详情参阅InitalContext 文档.

JavaGroups配置

先确保你在classpath指定的目录下放置了jgroups-all.jar文件(例如webapp put it in WEB-INF/lib目录),并且按下面格式添加JavaGroups 广播协议到你的oscache.properties:

cache.event.listeners=com.opensymphony.oscache.plugins.clustersupport.JavaGroupsBroadcastingListener

在大多数情形下这样就可以了。OSCache将通过LAN广播任何数据涌流,由于文件大小的原因,jgroups-all.jar库不包含在分发的二进制包中,然而你可以通过下载完全的OSCache分发包或通过访问 JavaGroups website来获得.

如果你想在同一个LAN上运行多于一个的OSCache集群机,你必须使用不同的多播IP地址。这允许缓存存在分开的多播组中,其不会干扰其它的组.通过oscache.propertie文件 的cache.cluster.multicast.ip 属性可以设置你使用的IP。默认值为:231.12.21.132,然而你可以使用任何D类IP地址。D类地址在224.0.0.0 ~ 239.255.255.255之间.

如果你不仅仅想控制多播的属性(例如,设置网络时间溢出或TTL),你可以使用cache.cluster.properties 配置属性。使用该属性待替cache.cluster.multicast.ip property即可。缺省值为:

UDP(mcast_addr=231.12.21.132;mcast_port=45566;ip_ttl=32;\

mcast_send_buf_size=150000;mcast_recv_buf_size=80000):\

PING(timeout=2000;num_initial_members=3):\

MERGE2(min_interval=5000;max_interval=10000):\

FD_SOCK:VERIFY_SUSPECT(timeout=1500):\

pbcast.NAKACK(gc_lag=50;retransmit_timeout=300,600,1200,2400,4800;max_xmit_size=8192):\

UNICAST(timeout=300,600,1200,2400):\

pbcast.STABLE(desired_avg_gossip=20000):\

FRAG(frag_size=8096;down_thread=false;up_thread=false):\

pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false;print_local_addr=true)

i)        资料编号NO205

用OSCache进行缓存对象”的研究

基于GeneralCacheAdministrator类来写的BaseCache类

package com.klstudio.cache;

import java.util.Date;

import com.opensymphony.oscache.base.NeedsRefreshException;
import com.opensymphony.oscache.general.GeneralCacheAdministrator;

public class BaseCache extends GeneralCacheAdministrator {
 //
过期时间(单位为秒);
 private int refreshPeriod;
 //关键字前缀字符;
 private String keyPrefix; 
 private static final long serialVersionUID = -4397192926052141162L; 
 public BaseCache(String keyPrefix,int refreshPeriod){
  super();
  this.keyPrefix = keyPrefix;
  this.refreshPeriod = refreshPeriod;
 }
 //添加被缓存的对象;
 public void put(String key,Object value){
  this.putInCache(this.keyPrefix+"_"+key,value);
 }
 //删除被缓存的对象;
 public void remove(String key){
  this.flushEntry(this.keyPrefix+"_"+key);
 }
 //删除所有被缓存的对象;
 public void removeAll(Date date){
  this.flushAll(date);
 } 
 public void removeAll(){
  this.flushAll();
 }
 //获取被缓存的对象;
 public Object get(String key) throws Exception{
  try{
   return this.getFromCache(this.keyPrefix+"_"+key,this.refreshPeriod);
  } catch (NeedsRefreshException e) {
   this.cancelUpdate(this.keyPrefix+"_"+key);
   throw e;
  }

 } 
}

Java代码

package com.klstudio.cache;

import java.util.Date;

import com.opensymphony.oscache.base.NeedsRefreshException;
import com.opensymphony.oscache.general.GeneralCacheAdministrator;

public class BaseCache extends GeneralCacheAdministrator {
 //
过期时间(单位为秒);
 private int refreshPeriod;
 //关键字前缀字符;
 private String keyPrefix; 
 private static final long serialVersionUID = -4397192926052141162L; 
 public BaseCache(String keyPrefix,int refreshPeriod){
  super();
  this.keyPrefix = keyPrefix;
  this.refreshPeriod = refreshPeriod;
 }
 //添加被缓存的对象;
 public void put(String key,Object value){
  this.putInCache(this.keyPrefix+"_"+key,value);
 }
 //删除被缓存的对象;
 public void remove(String key){
  this.flushEntry(this.keyPrefix+"_"+key);
 }
 //删除所有被缓存的对象;
 public void removeAll(Date date){
  this.flushAll(date);
 } 
 public void removeAll(){
  this.flushAll();
 }
 //获取被缓存的对象;
 public Object get(String key) throws Exception{
  try{
   return this.getFromCache(this.keyPrefix+"_"+key,this.refreshPeriod);
  } catch (NeedsRefreshException e) {
   this.cancelUpdate(this.keyPrefix+"_"+key);
   throw e;
  }

 } 
}

package com.klstudio;

import com.klstudio.News;
import com.klstudio.cache.BaseCache;

public class CacheManager { 
 private BaseCache newsCache; 
 private static CacheManager instance;
 private static Object lock = new Object(); 
 public CacheManager() {
     //
这个根据配置文件来,初始BaseCache而已;
  newsCache = new BaseCache("news",1800);  
 } 
 public static CacheManager getInstance(){
  if (instance == null){
   synchronized( lock ){
    if (instance == null){
     instance = new CacheManager();
    }
   }
  }
  return instance;
 }

 public void putNews(News news) {
  // TODO
自动生成方法存根
  newsCache.put(news.getID(),news);
 }

 public void removeNews(String newsID) {
  // TODO
自动生成方法存根
  newsCache.remove(newsID);
 }

 public News getNews(String newsID) {
  // TODO
自动生成方法存根
  try {
   return (News) newsCache.get(newsID);
  } catch (Exception e) {
   // TODO 自动生成 catch 块
   System.out.println("getNews>>newsID["+newsID+"]>>"+e.getMessage());
   News news = new News(newsID);
   this.putNews(news);
   return news;
  }
 }

 public void removeAllNews() {
  // TODO
自动生成方法存根
  newsCache.removeAll();
 }

}

Java代码

package com.klstudio;

import com.klstudio.News;
import com.klstudio.cache.BaseCache;

public class CacheManager { 
 private BaseCache newsCache; 
 private static CacheManager instance;
 private static Object lock = new Object(); 
 public CacheManager() {
     //
这个根据配置文件来,初始BaseCache而已;
  newsCache = new BaseCache("news",1800);  
 } 
 public static CacheManager getInstance(){
  if (instance == null){
   synchronized( lock ){
    if (instance == null){
     instance = new CacheManager();
    }
   }
  }
  return instance;
 }

 public void putNews(News news) {
  // TODO
自动生成方法存根
  newsCache.put(news.getID(),news);
 }

 public void removeNews(String newsID) {
  // TODO
自动生成方法存根
  newsCache.remove(newsID);
 }

 public News getNews(String newsID) {
  // TODO
自动生成方法存根
  try {
   return (News) newsCache.get(newsID);
  } catch (Exception e) {
   // TODO 自动生成 catch 块
   System.out.println("getNews>>newsID["+newsID+"]>>"+e.getMessage());
   News news = new News(newsID);
   this.putNews(news);
   return news;
  }
 }

 public void removeAllNews() {
  // TODO
自动生成方法存根
  newsCache.removeAll();
 }

}

j)       资料编号NO206

oscache 基本用法

   1,设置缓存

      <%@ taglib uri="/WEB-INF/tlds/oscache.tld" prefix="oscache" %>

       <oscache:cache key=”cacheKey” time=”300” scope=”application”>

被缓存的列表          

</oscache:cache>  

其中,cacheKey和time可以自己动态构件,scope(缓存范围) 可以是ession、application

     注意:cacheKey或者time如果是jsp表达式时,如:key=”<%=”string”+variable%>”而不是:key=”string<%=variable%>”,写法要注意,否则页面会报错

     2,刷新缓存

       <%@ taglib uri="/WEB-INF/tlds/oscache.tld" prefix="oscache" %>

        <oscache:flush key=”cacheKey” scope=”application” />

     3,分组缓存

       <cache:flush group='b' scope='application'/>

        <cache:cachekey='cacheKey_1' groups='a,b' duration='5s'>

        这里面的内容被缓存到键值为cacheKey_1,组名为a和b的缓存中,正常情况下,每隔5秒钟刷新一 次,但受上面标签“<cache:flush group='b' scope='application'/>”的影响,它将随每次页面的刷新而刷新

        </cache:cache>

        <cache:cachekey='cacheKey_2' groups='a' duration='5s'>

        这里面的内容被缓存到键值为cacheKey_2,组名为a的缓存中,它将每隔5秒中刷新一次

        </cache:cache>

        <cache:cachekey='cacheKey_3' duration='20s'>

        这里面的内容被缓存到cacheKey_3,组a,b中,组是通过标签<cache: addgroup>而添加的,它也会受本页开头标签“<cache:flush group='b' scope='application'/>”的影响而随页面刷新而刷新

        <cache:addgroup group='a'/>

        <cache:addgroup group='b'/>

        </cache:cache>

        <cache:cachekey='cacheKey_4' duration='20s'>

         这里面的内容被缓存到cacheKey_4,组a,b中,组是通过标签<cache: addgroups>而添加的,它也会受本页开头标签“<cache:flush group='b' scope='application'/>”的影响而随页面刷新而刷新

       <cache:addgroups groups='a,b'/>

        </cache:cache>

(三)  几个著名的Java缓存技术

OSCache

  OSCache是个一个广泛采用的高性能的J2EE缓存框架,OSCache能用于任何java应用程序的普通的缓存解决方案。

  OSCache有以下特点:

  缓存任何对象,你可以不受限制的缓存部分jsp页面或HTTP请求,任何java对象都可以缓存。

  拥有全面的API--OSCache API给你全面的程序来控制所有的OSCache特性。

  永久缓存--缓存能随意的写入硬盘,因此答应昂贵的创建(eXPensive-to-create)数据来保持缓存,甚至能让应用重启。

  支持集群--集群缓存数据能被单个的进行参数配置,不需要修改代码。

  缓存记录的过期--你可以有最大限度的控制缓存对象的过期,包括可插入式的刷新策略(假如默认性能不需要时)。

   

Java Caching System

  JSC(Java Caching System)是一个用分布式的缓存系统,是基于服务器的java应用程序。它是通过提供治理各种动态缓存数据来加速动态web应用。

  JCS和其他缓存系统一样,也是一个用于高速读取,低速写入的应用程序。

  动态内容和报表系统能够获得更好的性能。

  假如一个网站,有重复的网站结构,使用间歇性更新方式的数据库(而不是连续不断的更新数据库),被重复搜索出相同结果的,就能够通过执行缓存方式改进其性能和伸缩性。

  官方网站 http://jakarta.apache.org/turbine/jcs/

  

  EHCache

  EHCache 是一个纯java的在进程中的缓存,它具有以下特性:快速,简单,为Hibernate2.1充当可插入的缓存,最小的依靠性,全面的文档和测试。

  官方网站 http://ehcache.sourceforge.net/

  

  JCache

  JCache是个开源程序,正在努力成为JSR-107开源规范,JSR-107规范已经很多年没改变了。这个版本仍然是构建在最初的功能定义上。

  官方网站 http://jcache.sourceforge.net/

  

  ShiftOne

  ShiftOne Java Object Cache是一个执行一系列严格的对象缓存策略的Java lib,就像一个轻量级的配置缓存工作状态的框架。

  官方网站 http://jocache.sourceforge.net/

  

  SwarmCache

  SwarmCache是一个简单且有效的分布式缓存,它使用ip multicast与同一个局域网的其他主机进行通讯,是非凡为集群和数据驱动web应用程序而设计的。SwarmCache能够让典型的读操作大大超过写操作的这类应用提供更好的性能支持。

  SwarmCache使用JavaGroups来治理从属关系和分布式缓存的通讯。

  官方网站 http://swarmcache.sourceforge.net

  

  TreeCache / JBossCache

  JBossCache是一个复制的事务处理缓存,它答应你缓存企业级应用数据来更好的改善性能。缓存数据被自动复制,让你轻松进行JBoss服务器之间的集群工作。JBossCache能够通过JBoss应用服务或其他J2EE容器来运行一个MBean服务,当然,它也能独立运行。

  JBossCache包括两个模块:TreeCache和TreeCacheAOP。

  TreeCache --是一个树形结构复制的事务处理缓存。

  TreeCacheAOP --是一个“面向对象”缓存,它使用AOP来动态治理POJO(Plain Old Java Objects)

  注:AOP是OOP的延续,是aspect Oriented PRogramming的缩写,意思是面向方面编程。

  官方网站 http://www.jboss.org/prodUCts/jbosscache

  

  WhirlyCache

Whirlycache是一个快速的、可配置的、存在于内存中的对象的缓存。它能够通过缓存对象来加快网站或应用程序的速度,否则就必须通过查询数据库或其他代价较高的处理程序来建立。

官方网站 https://whirlycache.dev.java.net/

更多相关推荐:
pda技术报告目录

PDA的技术报告目录PDAParenteralDrugAssociation注射用药物协会PDA技术报告目录PDAPublicationsTechnicalMethodsBulletinNo1Extractab...

pda实训报告

一PDA的功能PDA是PersonalDigitalAsistent的简称它的物理含义是非常广泛的商务通好易通笔记本电脑电子记事本名片管理器等都属于PDA由于PDA做得巧玲珑还具有电脑功能因此又称为掌心电脑PD...

20xx《EDA技术基础》【设计】实验总结报告模板及要求(1)

EDA技术基础音乐播放器设计性实验20xx1120xx346郭斌电子信息科学与技术物电学院0803班湖北师范学院电工电子实验教学省级示范中心电子版实验报告一任务解析以前用51单片机制作了一个可演奏的电子琴学习了...

EDA技术4选1多路选择器实验报告

EDA技术实验报告实验报告学院电子信息工程学院专业电子信息工程技术20xx年12月1EDA技术实验报告2EDA技术实验报告EDA技术实验报告4

EDA技术数字时钟实验报告

JIUJIANGUNIVERSITYEDA技术实验报告实验目的实验名称院系班级学号实验室专业姓名日期数字时钟电子工程学院B111152号实验楼307电子信息工程技术高芬20xx年12月15日设计一个可以计时的数...

EDA技术及应用 实验报告

EDA技术及应用实验报告系部电子通信工程系指导教师实验一点亮LED设计一实验目的通过此实验让用户逐步了解熟悉和掌握FPGA开发软件Quartus的使用方法及VerilogHDL的编程方法本实验力求以详细的步骤和...

EDA技术及应用实验报告(完整版纯手打)

EDA技术及应用实验报告系部指导教师学号姓名实验一点亮LED设计一实验目的通过此实验让用户逐步了解熟悉和掌握FPGA开发软件QuartusII的使用方法及VerilogHDL的编程方法本实验力求以详细的步骤和讲...

《EDA技术》实验报告模板20xx

EDA技术课程实验报告姓名学号班级同组者指导教师许慧燕信息科学与工程学院20xx20xx学年第一学期第1页EDA技术课程实验报告学生姓名所在班级记分及评价一实验名称实验13简单数字电子钟的设计原理图输入设计方法...

EDA技术及应用实验报告四

EDA技术及应用实验报告EDA技术及应用实验报告实验四数字频率计的设计学班学指导教生姓名级号师张志翔电子信息工程1203班12401720xx220xx428112EDA技术及应用实验报告实验四数字频率计的设计...

EDA技术使用教程VHDL版实验报告1

EDA技术实验报告实验报告系别电子电气工程系课程EDA技术1EDA技术实验报告2EDA技术实验报告EDA技术实验报告4

国家标准GB7713-87:科学技术报告、学位论文和学术论文的编写格式

国家标准GB771387科学技术报告学位论文和学术论文的编写格式1引言11制订本标准的目的是为了统一科学技术报告学位论文和学术论文以下简称报告论文的撰写和编辑的格式便利信息系统的收集存储处理加工检索利用交流传播...

技术汇报材料

忻保高速公路建设管理处第三阶段劳动竞赛检查汇报材料忻保高速公路路基工程五合同段项目部二00九年十一月五日工作汇报尊敬的各位领导大家好首先我代表忻保高速路基五合同段项目部的全体建设者对各位领导的到来表示热烈的欢迎...

pda技术报告(2篇)