缓存服务的功能:缓存服务可提高对象的重用性,减少读取数据库、计算等操作步骤;为此付出的代价是对象使用前的判断和对象存储内存空间的开销。
作者对缓存服务的设计特点:基于XmlDocument 对象,对象存储的名称信息可包含模块名、用户名、自定名,存储名有自描述性,易于理解;对象的获取和删除可基于某个组某个模块全部获取全部删除。
缓存服务对象 Cache:
存储缓存对象的对象的接口:
缓存服务对象的实现依赖配置文件配置项 Framework/ SAF.Cache/ CacheStrategy:
ICacheStrategy 缓存接口的实现 DefaultCacheStrategy ;
缓存对象可自定,自定缓存类需实现 1.继承自 ICacheStrategy ;2.配置文件中写明;
使用Hashtable 作为存储缓存对象的数据结构:
使用缓存服务的代码 Class1:
作者对缓存服务的设计特点:基于XmlDocument 对象,对象存储的名称信息可包含模块名、用户名、自定名,存储名有自描述性,易于理解;对象的获取和删除可基于某个组某个模块全部获取全部删除。
缓存服务对象 Cache:
/// <summary>
/// SAF.Cache is an object caching service that
/// present the cached object in an hierarchical structure.
/// It uses a pluggable object storage mechnism or cache strategy
/// to storage the objects.
/// </summary>
public class Cache
{
private XmlElement objectXmlMap ;
private static SAF.Cache.ICacheStrategy cs;
private static Cache cache;
private XmlDocument rootXml = new XmlDocument();
/// <summary>
/// Private construtor, required for singleton design pattern.
/// </summary>
private Cache()
{
//retrieve setting from configuration file
ConfigurationManager cm = (ConfigurationManager)ConfigurationSettings.GetConfig("Framework");
// 读取配置文件信息,建立缓存对象存储对象
cs = (ICacheStrategy)cm.CacheConfig.GetCacheStrategy();
//create an Xml used as a map between xml expression and object cached in the
//physical storage.
objectXmlMap = rootXml.CreateElement("Cache");
//build the internal xml document.
rootXml.AppendChild(objectXmlMap);
}
/// <summary>
/// Singlton method used to return the instance of Cache class
/// </summary>
/// <returns></returns>
public static Cache GetSAFCacheService()
{
if (cache == null)
{
cache = new Cache();
}
return cache;
}
/// <summary>
/// Add the object to the underlying storage and Xml mapping document
/// </summary>
/// <param name="xpath">the hierarchical location of the object in Xml document </param>
/// <param name="o">the object to be cached</param>
public virtual void AddObject(string xpath, object o)
{
//clear up the xpath expression
string newXpath = PrepareXpath(xpath);
int separator = newXpath.LastIndexOf("/");
//find the group name
string group = newXpath.Substring(0,separator );
//find the item name
string element = newXpath.Substring(separator + 1);
XmlNode groupNode = objectXmlMap.SelectSingleNode(group);
//determin if group is already exist?, if not, create one.
if (groupNode == null)
{
lock(this)
{
//build the xml tree
groupNode = CreateNode(group);
}
}
//get a unique key to identity of object, it is used to map
//between xml and object key used in the cache strategy
string objectId = System.Guid.NewGuid().ToString();
//create an new element and new attribute for this perticular object
XmlElement objectElement = objectXmlMap.OwnerDocument.CreateElement(element);
XmlAttribute objectAttribute =objectXmlMap.OwnerDocument.CreateAttribute("objectId");
objectAttribute.Value = objectId;
objectElement.Attributes.Append(objectAttribute);
//Add the object element to the Xml document
groupNode.AppendChild(objectElement);
//add the object to the underlying storage through cache strategy
cs.AddObject(objectId,o);
}
/// <summary>
/// Retrieve the cached object using its hierarchical location
/// </summary>
/// <param name="xpath">hierarchical location of the object in xml document</param>
/// <returns>cached object </returns>
public virtual object RetrieveObject(string xpath)
{
object o = null;
XmlNode node =objectXmlMap.SelectSingleNode(PrepareXpath(xpath));
//if the hierarchical location existed in the xml, retrieve the object
//otherwise, return the object as null
if ( node != null)
{
string objectId = node.Attributes["objectId"].Value;
//retrieve the object through cache strategy
o = cs.RetrieveObject(objectId);
}
return o;
}
/// <summary>
/// Remove the object from the storage and clear the Xml assocated with
/// the object
/// </summary>
/// <param name="xpath">hierarchical locatioin of the object</param>
public virtual void RemoveObject(string xpath)
{
XmlNode result = objectXmlMap.SelectSingleNode(PrepareXpath(xpath));
//check if the xpath refers to a group(container) or
//actual element for cached object
if (result.HasChildNodes)
{
//remove all the cached object in the hastable
//and remove all the child nodes
XmlNodeList objects = result.SelectNodes("*[@objectId]");
string objectId ="";
foreach (XmlNode node in objects)
{
objectId = node.Attributes["objectId"].Value;
node.ParentNode.RemoveChild(node);
//use cache strategy to remove the objects from the
//underlying storage
cs.RemoveObject(objectId);
}
}
else
{
//just remove the element node and the object associate with it
string objectId = result.Attributes["objectId"].Value;
result.ParentNode.RemoveChild(result);
cs.RemoveObject(objectId);
}
}
/// <summary>
/// Retrive a list of object under a hierarchical location
/// </summary>
/// <param name="xpath">hierarchical location</param>
/// <returns>an array of objects</returns>
public virtual object[] RetrieveObjectList(string xpath)
{
XmlNode group = objectXmlMap.SelectSingleNode(PrepareXpath(xpath));
XmlNodeList results = group.SelectNodes(PrepareXpath(xpath) + "/*[@objectId]");
ArrayList objects = new ArrayList();
string objectId= null;
//loop through each node and link the object in object[]
//to objects stored via cache strategy
foreach (XmlNode result in results)
{
objectId = result.Attributes["objectId"].Value;
objects.Add(cs.RetrieveObject(objectId));
}
//convert the ArrayList to object[]
return (object[])objects.ToArray(typeof(System.Object));
}
/// <summary>
/// CreateNode is responsible for creating the xml tree that is
/// specificed in the hierarchical location of the object.
/// </summary>
/// <param name="xpath">hierarchical location</param>
/// <returns></returns>
private XmlNode CreateNode(string xpath)
{
string[] xpathArray = xpath.Split('/');
string root = "";
XmlNode parentNode = (XmlNode)objectXmlMap;
//loop through the array of levels and create the corresponding node for each level
//skip the root node.
for (int i = 1; i < xpathArray.Length; i ++)
{
XmlNode node = objectXmlMap.SelectSingleNode(root + "/" + xpathArray[i]);
// if the current location doesn't exist, build one
//otherwise set the current locaiton to the it child location
if (node == null)
{
XmlElement newElement= objectXmlMap.OwnerDocument.CreateElement(xpathArray[i]);
parentNode.AppendChild(newElement);
}
//set the new location to one level lower
root = root + "/" + xpathArray[i];
parentNode = objectXmlMap.SelectSingleNode(root);
}
return parentNode;
}
/// <summary>
/// clean up the xpath so that extra '/' is removed
/// </summary>
/// <param name="xpath">hierarchical location</param>
/// <returns></returns>
private string PrepareXpath(string xpath)
{
string[] xpathArray = xpath.Split('/');
xpath ="/Cache";
foreach (string s in xpathArray)
{
if (s != "")
{
xpath = xpath + "/" + s ;
}
}
return xpath;
}
}
/// SAF.Cache is an object caching service that
/// present the cached object in an hierarchical structure.
/// It uses a pluggable object storage mechnism or cache strategy
/// to storage the objects.
/// </summary>
public class Cache
{
private XmlElement objectXmlMap ;
private static SAF.Cache.ICacheStrategy cs;
private static Cache cache;
private XmlDocument rootXml = new XmlDocument();
/// <summary>
/// Private construtor, required for singleton design pattern.
/// </summary>
private Cache()
{
//retrieve setting from configuration file
ConfigurationManager cm = (ConfigurationManager)ConfigurationSettings.GetConfig("Framework");
// 读取配置文件信息,建立缓存对象存储对象
cs = (ICacheStrategy)cm.CacheConfig.GetCacheStrategy();
//create an Xml used as a map between xml expression and object cached in the
//physical storage.
objectXmlMap = rootXml.CreateElement("Cache");
//build the internal xml document.
rootXml.AppendChild(objectXmlMap);
}
/// <summary>
/// Singlton method used to return the instance of Cache class
/// </summary>
/// <returns></returns>
public static Cache GetSAFCacheService()
{
if (cache == null)
{
cache = new Cache();
}
return cache;
}
/// <summary>
/// Add the object to the underlying storage and Xml mapping document
/// </summary>
/// <param name="xpath">the hierarchical location of the object in Xml document </param>
/// <param name="o">the object to be cached</param>
public virtual void AddObject(string xpath, object o)
{
//clear up the xpath expression
string newXpath = PrepareXpath(xpath);
int separator = newXpath.LastIndexOf("/");
//find the group name
string group = newXpath.Substring(0,separator );
//find the item name
string element = newXpath.Substring(separator + 1);
XmlNode groupNode = objectXmlMap.SelectSingleNode(group);
//determin if group is already exist?, if not, create one.
if (groupNode == null)
{
lock(this)
{
//build the xml tree
groupNode = CreateNode(group);
}
}
//get a unique key to identity of object, it is used to map
//between xml and object key used in the cache strategy
string objectId = System.Guid.NewGuid().ToString();
//create an new element and new attribute for this perticular object
XmlElement objectElement = objectXmlMap.OwnerDocument.CreateElement(element);
XmlAttribute objectAttribute =objectXmlMap.OwnerDocument.CreateAttribute("objectId");
objectAttribute.Value = objectId;
objectElement.Attributes.Append(objectAttribute);
//Add the object element to the Xml document
groupNode.AppendChild(objectElement);
//add the object to the underlying storage through cache strategy
cs.AddObject(objectId,o);
}
/// <summary>
/// Retrieve the cached object using its hierarchical location
/// </summary>
/// <param name="xpath">hierarchical location of the object in xml document</param>
/// <returns>cached object </returns>
public virtual object RetrieveObject(string xpath)
{
object o = null;
XmlNode node =objectXmlMap.SelectSingleNode(PrepareXpath(xpath));
//if the hierarchical location existed in the xml, retrieve the object
//otherwise, return the object as null
if ( node != null)
{
string objectId = node.Attributes["objectId"].Value;
//retrieve the object through cache strategy
o = cs.RetrieveObject(objectId);
}
return o;
}
/// <summary>
/// Remove the object from the storage and clear the Xml assocated with
/// the object
/// </summary>
/// <param name="xpath">hierarchical locatioin of the object</param>
public virtual void RemoveObject(string xpath)
{
XmlNode result = objectXmlMap.SelectSingleNode(PrepareXpath(xpath));
//check if the xpath refers to a group(container) or
//actual element for cached object
if (result.HasChildNodes)
{
//remove all the cached object in the hastable
//and remove all the child nodes
XmlNodeList objects = result.SelectNodes("*[@objectId]");
string objectId ="";
foreach (XmlNode node in objects)
{
objectId = node.Attributes["objectId"].Value;
node.ParentNode.RemoveChild(node);
//use cache strategy to remove the objects from the
//underlying storage
cs.RemoveObject(objectId);
}
}
else
{
//just remove the element node and the object associate with it
string objectId = result.Attributes["objectId"].Value;
result.ParentNode.RemoveChild(result);
cs.RemoveObject(objectId);
}
}
/// <summary>
/// Retrive a list of object under a hierarchical location
/// </summary>
/// <param name="xpath">hierarchical location</param>
/// <returns>an array of objects</returns>
public virtual object[] RetrieveObjectList(string xpath)
{
XmlNode group = objectXmlMap.SelectSingleNode(PrepareXpath(xpath));
XmlNodeList results = group.SelectNodes(PrepareXpath(xpath) + "/*[@objectId]");
ArrayList objects = new ArrayList();
string objectId= null;
//loop through each node and link the object in object[]
//to objects stored via cache strategy
foreach (XmlNode result in results)
{
objectId = result.Attributes["objectId"].Value;
objects.Add(cs.RetrieveObject(objectId));
}
//convert the ArrayList to object[]
return (object[])objects.ToArray(typeof(System.Object));
}
/// <summary>
/// CreateNode is responsible for creating the xml tree that is
/// specificed in the hierarchical location of the object.
/// </summary>
/// <param name="xpath">hierarchical location</param>
/// <returns></returns>
private XmlNode CreateNode(string xpath)
{
string[] xpathArray = xpath.Split('/');
string root = "";
XmlNode parentNode = (XmlNode)objectXmlMap;
//loop through the array of levels and create the corresponding node for each level
//skip the root node.
for (int i = 1; i < xpathArray.Length; i ++)
{
XmlNode node = objectXmlMap.SelectSingleNode(root + "/" + xpathArray[i]);
// if the current location doesn't exist, build one
//otherwise set the current locaiton to the it child location
if (node == null)
{
XmlElement newElement= objectXmlMap.OwnerDocument.CreateElement(xpathArray[i]);
parentNode.AppendChild(newElement);
}
//set the new location to one level lower
root = root + "/" + xpathArray[i];
parentNode = objectXmlMap.SelectSingleNode(root);
}
return parentNode;
}
/// <summary>
/// clean up the xpath so that extra '/' is removed
/// </summary>
/// <param name="xpath">hierarchical location</param>
/// <returns></returns>
private string PrepareXpath(string xpath)
{
string[] xpathArray = xpath.Split('/');
xpath ="/Cache";
foreach (string s in xpathArray)
{
if (s != "")
{
xpath = xpath + "/" + s ;
}
}
return xpath;
}
}
存储缓存对象的对象的接口:
/// <summary>
/// the interface for cache strategy.
/// each class that is pluggable to the SAF.Cache must
/// implement this interface.
/// </summary>
public interface ICacheStrategy
{
void AddObject(string objId, object o);
void RemoveObject(string objId);
object RetrieveObject(string objId);
}
/// the interface for cache strategy.
/// each class that is pluggable to the SAF.Cache must
/// implement this interface.
/// </summary>
public interface ICacheStrategy
{
void AddObject(string objId, object o);
void RemoveObject(string objId);
object RetrieveObject(string objId);
}
缓存服务对象的实现依赖配置文件配置项 Framework/ SAF.Cache/ CacheStrategy:
<
configuration
>
< configSections >
< section name = " Framework " type = " SAF.Configuration.ConfigurationHandler,SAF.Configuration " />
< section name = " Application " type = " SAF.Configuration.ConfigurationHandler,SAF.Configuration " />
</ configSections >
< Framework type = " SAF.Configuration.ConfigurationManager,SAF.Configuration " >
< SAF.Cache >
< CacheStrategy type = " SAF.Cache.DefaultCacheStrategy,SAF.Cache " />
</ SAF.Cache >
</ Framework >
</ configuration >
< configSections >
< section name = " Framework " type = " SAF.Configuration.ConfigurationHandler,SAF.Configuration " />
< section name = " Application " type = " SAF.Configuration.ConfigurationHandler,SAF.Configuration " />
</ configSections >
< Framework type = " SAF.Configuration.ConfigurationManager,SAF.Configuration " >
< SAF.Cache >
< CacheStrategy type = " SAF.Cache.DefaultCacheStrategy,SAF.Cache " />
</ SAF.Cache >
</ Framework >
</ configuration >
ICacheStrategy 缓存接口的实现 DefaultCacheStrategy ;
缓存对象可自定,自定缓存类需实现 1.继承自 ICacheStrategy ;2.配置文件中写明;
使用Hashtable 作为存储缓存对象的数据结构:
/// <summary>
/// the sample cache strategy implementation which
/// shows how you create an pluggable component for SAF.Cache
/// to customize the way object is cahced and retrieved.
/// </summary>
public class DefaultCacheStrategy : ICacheStrategy
{
private Hashtable objectTable;
/// <summary>
/// constructor to instantiate the internal hashtable.
/// </summary>
public DefaultCacheStrategy()
{
objectTable = new Hashtable();
}
/// <summary>
/// Add an object to the underlying storage
/// </summary>
/// <param name="objId">key for the object</param>
/// <param name="o">object</param>
public void AddObject(string objId, object o)
{
objectTable.Add(objId,o);
}
/// <summary>
/// Remove an object from the underlying storage
/// </summary>
/// <param name="objId">key for the object</param>
public void RemoveObject(string objId)
{
objectTable.Remove(objId);
}
/// <summary>
/// Retrieve an object from the underlying storage
/// </summary>
/// <param name="objId">key for the object</param>
/// <returns>object</returns>
public object RetrieveObject(string objId)
{
return objectTable[objId];
}
}
/// the sample cache strategy implementation which
/// shows how you create an pluggable component for SAF.Cache
/// to customize the way object is cahced and retrieved.
/// </summary>
public class DefaultCacheStrategy : ICacheStrategy
{
private Hashtable objectTable;
/// <summary>
/// constructor to instantiate the internal hashtable.
/// </summary>
public DefaultCacheStrategy()
{
objectTable = new Hashtable();
}
/// <summary>
/// Add an object to the underlying storage
/// </summary>
/// <param name="objId">key for the object</param>
/// <param name="o">object</param>
public void AddObject(string objId, object o)
{
objectTable.Add(objId,o);
}
/// <summary>
/// Remove an object from the underlying storage
/// </summary>
/// <param name="objId">key for the object</param>
public void RemoveObject(string objId)
{
objectTable.Remove(objId);
}
/// <summary>
/// Retrieve an object from the underlying storage
/// </summary>
/// <param name="objId">key for the object</param>
/// <returns>object</returns>
public object RetrieveObject(string objId)
{
return objectTable[objId];
}
}
使用缓存服务的代码 Class1:
using
System;
using SAF.Cache;
using SAF.Configuration;
using System.Configuration;
namespace TestConsole
{
/// <summary>
/// The demo shows how to use the SAF.Cache service
/// to add, remove and retrieve objects from the cache
/// </summary>
class Class1
{
[STAThread]
static void Main(string[] args)
{
// 获取缓存服务对象
Cache cache = SAF.Cache.Cache.GetSAFCacheService();
// 缓存服务内存入一些对象
cache.AddObject("/WebApplication/Users/Xin", "customer xin");
cache.AddObject("/WebApplication/Users/Mike", "customer mike");
cache.AddObject("/WebApplication/Users/Steve", "customer steve");
cache.AddObject("/WebApplication/GlobalData", "1/1/2003");
// 获取同一组的缓存对象
object[] objects = cache.RetrieveObjectList("/WebApplication/Users");
foreach (object o in objects)
{
Console.WriteLine("Customer in cache: {0}", o.ToString());
}
// 获取一个缓存对象
string time =(string) cache.RetrieveObject("/WebApplication/GlobalData");
string name = (string) cache.RetrieveObject("/WebApplication/Users/Xin");
// 移除一个缓存对象
cache.RemoveObject("/WebApplication/GlobalData");
// 移除同一组的所有缓存对象
cache.RemoveObject("/WebApplication/Users");
Console.WriteLine("Press Enter to finish");
Console.ReadLine();
}
}
}
using SAF.Cache;
using SAF.Configuration;
using System.Configuration;
namespace TestConsole
{
/// <summary>
/// The demo shows how to use the SAF.Cache service
/// to add, remove and retrieve objects from the cache
/// </summary>
class Class1
{
[STAThread]
static void Main(string[] args)
{
// 获取缓存服务对象
Cache cache = SAF.Cache.Cache.GetSAFCacheService();
// 缓存服务内存入一些对象
cache.AddObject("/WebApplication/Users/Xin", "customer xin");
cache.AddObject("/WebApplication/Users/Mike", "customer mike");
cache.AddObject("/WebApplication/Users/Steve", "customer steve");
cache.AddObject("/WebApplication/GlobalData", "1/1/2003");
// 获取同一组的缓存对象
object[] objects = cache.RetrieveObjectList("/WebApplication/Users");
foreach (object o in objects)
{
Console.WriteLine("Customer in cache: {0}", o.ToString());
}
// 获取一个缓存对象
string time =(string) cache.RetrieveObject("/WebApplication/GlobalData");
string name = (string) cache.RetrieveObject("/WebApplication/Users/Xin");
// 移除一个缓存对象
cache.RemoveObject("/WebApplication/GlobalData");
// 移除同一组的所有缓存对象
cache.RemoveObject("/WebApplication/Users");
Console.WriteLine("Press Enter to finish");
Console.ReadLine();
}
}
}