使用 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 文件 — 一個純內存緩存配置:
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)時使用了一個內存區域和一個磁碟區域:
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 的基本用法
學習 JCS 基礎知識的一個好方法是查看 API 最常用的方法。最好從初始化區域開始。初始化 JCS 緩存區域對象能使您訪問大部分所需的常用方法。清單 3 初始化 JCS 對象並獲得一個默認緩存區域實例:
// Initialize the JCS object and get an instance of the default cache region JCS cache = JCS.getInstance("default"); |
檢索 JCS 實例后,可以調用最需要的方法。put 方法將一個新對象放入緩存中。接下來只需一個 key(第一個參數)和一個 value(第二個參數)。清單 4 顯示一個基本示例:
// Set up String key = "key0"; String value = "value0"; // Place a new object in the cache cache.put(key, value); |
清單 4 中的示例使用字元串值作為參數,但是您可以使用任何對象。
檢索緩存對象只不過是使用 JCS 提供的 get 方法。清單 5 顯示了一個簡單示例。同樣,本例使用了一個字元串參數,但您可以使用任何對象。
// Retrieve a cached object String cachedData = (String)cache.get(key); |
測試緩存數據的有效性可能是處理緩存系統時需要使用的另一種方法。在 JCS 中,沒有定義只測試緩存項是否存在的測試緩存方法。但是 get 方法的返回值可以幫助您。清單 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 顯示了如何使用這些方法:
// 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 類:
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 對象相關的管理和緩存功能。在本例中,管理器將處理三大任務:
如清單 9 所示,getBlog 方法檢索 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 對象,然後將這個對象放在緩存中。
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 方法來清除緩存對象。
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 中的例子顯示如何檢索緩存項的元數據:
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 驗證和其他輔助區域。(責任編輯:A6)
[火星人 ] 使用緩存構建更快的 Web 應用程序已經有468次圍觀