簡介:使用 Java™ 技術的 Web 開發人員可以使用緩存實用程序快速提 升他們的應用程序的性能。Java 緩存系統(Java Caching System,JCS)是一個 用於 Java 應用程序的強大分布式緩存系統,它是擁有簡單 API 的高度可配置的 工具。本文將概述 JCS 並展示如何使用它來提高 Web 應用程序的速度。
許多 Web 應用程序會根據桌面應用程序重新編寫;理想情況下,這些應用程 序的速度和可伸縮性應該與桌面版本一樣。幾乎所有 Web 應用程序都可以從速度 方面的增長獲益。緩存被頻繁查看但很少更改的數據是一種減少用戶等待時間的 有效方式。一個實用程序可以幫您實現這個目標,它使用簡單易用的 API 來輕松 處理數據緩存。開放源碼 JCS(即一個 Apache Jakarta 項目)就是這樣一種工 具。本文將說明如何配置和使用 JCS 來緩存 Web 應用程序的數據。
JCS 概述
JCS 是一個用 Java 語言編寫的緩存系統,可以使用它來創建 Java 桌面和 Web 應用程序。它提供了在緩存器中存儲數據、從緩存器中刪除數據等方 便機制。
使用 JCS 可以在各種指定的數據區域 中存儲緩存數據。JCS 定 義了 4 種類型的核心區域:內存區域、磁盤區域、外圍區域和遠程區域。可以結 合使用這些核心區域以在如何存儲緩存數據、將緩存數據存儲在什麼地方等方面 獲得更大的靈活性。您可以指定首次使用哪個區域,以及發生故障時轉移到哪個 區域。
內存區域
內存區域是一個使用最近最少算法(Least Recently Used,LRU)的純內存緩存區域。當內存緩存區域滿時,LRU 會首先刪 除最近最少使用的緩存數據。這個數據區域執行良好,大多數 JCS 用戶將它指定 為最先使用的默認緩存區域。
磁盤區域
磁盤區域是在 Web 服務器 的文件磁盤上緩存數據。為了提高性能,JCS 在文件磁盤上存儲實際緩存數據的 同時,會在內存中存儲緩存數據鍵。在首先使用內存區域的典型 JCS 配置中,任 何無法在內存區域中保存的數據都會寫入磁盤區域中。
外圍區域
外圍區域提供一種可配置方式來在多台服務器之間分發緩存數據。緩存數據服 務器必須有一個開放的用於偵聽的端口,而且必須創建一個套接字連接。這個區 域存在一個潛在問題,因為它不能保證各緩存之間的數據的一致性。但如果是按 計劃使用該區域,則不會出現這個問題。
遠程區域
遠程區域提供了一個使用遠程方法調用(RMI)API 的緩存區域。這個區域使 用一台遠程服務器處理緩存數據。這台遠程緩存服務器可以被多個 JCS 客戶端應 用程序用於存儲緩存數據。一些偵聽器被定義用於收集來自客戶端和服務器的請 求。這個緩存區域幫助減少串行化和多個連接點的開銷。
JCS 配置
配置 JCS 就是簡單地創建和填充一個 cache.ccf 文件。這個文件定義緩存應 該使用哪些區域,以及這些區域的屬性或選項。根據應用程序的需求配置這個文 件是一種快速擴展緩存的簡便方式。您可以指定許多適合配置的選項和屬性來滿 足需求。
清單 1 顯示的是最基本的 cache.ccf 文件 — 一個純內存緩存配置:
清單 1. JCS 的基本配置
jcs.default=jcs.default.cacheattributes=org.apache.jcs.engine.Compos iteCacheAttributes
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.CompositeCacheAttribu tes
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.CompositeCa cheAttributes
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.ElementAt tributes
jcs.region.OUR_REGION.elementattributes.IsEternal=false
jcs.auxiliary.DISK_REGION=org.apache.jcs.auxiliary.disk.indexed.Indexed DiskCacheFactory
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 中的示例顯示如何獲得此信息:
清單 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 驗證和其他輔助區域 。