asp.net SAF 中缓存服务的实现第3/5页

 更新时间:2008年08月08日 21:28:49   作者:  
对缓存的兴趣源于张子阳写的一篇文章《SAF 中缓存服务的实现》中的一个例子:

Cache类还包含两个私有方法。PreparePath()用于对输入的Xpath进行格式化,使其以构造函数中创建的根节点("Cache")作为根结点(这样做是可以使你在添加/获取对象时免去写根结点的麻烦);CreateNode() 用于根据XPath逐层深入地创建Xml结点。 C#复制代码
// 根据 XPath 创建一个结点    
private XmlNode CreateNode(string xpath) {    

    string[] xpathArray = xpath.Split('/');    
    string nodePath = "";    

    // 父节点初始化    
    XmlNode parentNode = (XmlNode)rootMap;      

    // 逐层深入 XPath 各层级,如果结点不存在则创建    
    // 比如 /DvdStore/Dvd/NoOneLivesForever    
    for (int i = 1; i < xpathArray.Length; i++) {    
      XmlNode node = rootMap.SelectSingleNode(nodePath + "/" + xpathArray[i]);    

       if (node == null) {    
           XmlElement newElement = rootMap.OwnerDocument.CreateElement(xpathArray[i]);   // 创建结点    
           parentNode.AppendChild(newElement);    
       }    

       // 创建新路径,更新父节点,进入下一级    
       nodePath = nodePath + "/" + xpathArray[i];    
       parentNode = rootMap.SelectSingleNode(nodePath);    
    }    

    return parentNode;    
}    

// 构建 XPath,使其以 /Cache 为根结点,并清除多于的"/"字符    
private string PrepareXPath(string xpath) {    
    string[] xpathArray = xpath.Split('/');    
    xpath = "/Cache";     // 这里的名称需与构造函数中创建的根结点名称对应    
    foreach (string s in xpathArray) {    
       if (s != "") {    
           xpath += "/" + s;    
       }    
    }    
    return xpath;    
}   
AddItem()方法用于向缓存中添加对象,包括了下面几个步骤: 
1、根据输入的XPath判断到达 叶结点 的路径是否已经存在,如果不存在,调用上面的CreateNode()方法,逐层创建结点。 
2、生成GUID,在组结点下创建 XmlNode 叶结点,为叶结点添加属性Key,并将值设为GUID。 
3、将对象保存至实际的位置,默认实现是一个Hashtable,通过调用ICacheStrategy.AddItem()方法来完成,并将Hashtable的Key设置为GUID。 

NOTE: 为了说明方便,这里有一个我对一类结点的命名--“组结点”。假设有XPath路径:/Cache/BookStore/Book/Title,那么/Cache/BookStore/Book即为“组结点”,称其为“组结点”,是因为其下可包含多个叶结点,比如 /Cache/BookStore/Book/Author 包含了叶结点 Author;而/Cache/BookStore/Book/Title 中的Title为叶结点,GUID存储在叶结点的属性中。需要注意 组结点 和 叶结点是相对的,对于路径 /Cache/BookStore/Book 来说,它的组结点就是“/Cache/BookStore”,而 Book是它的叶结点。 

下面是AddItem()方法的完整代码:
复制代码 代码如下:

// 添加对象,对象实际上还是添加到ICacheStrategy指定的存储位置,    
// 动态创建的 Xml 结点仅保存了对象的Id(key),用于映射两者间的关系    
public virtual void AddItem(string xpath, object obj) {    

    // 获取 Xpath,例如 /Cache/BookStore/Book/Title    
    string newXpath = PrepareXPath(xpath);    

    int separator = newXpath.LastIndexOf("/");    

    // 获取组结点的层叠顺序 ,例如 /Cache/BookStore/Book    
    string group = newXpath.Substring(0, separator);    

    // 获取叶结点名称,例如 Title    
    string element = newXpath.Substring(separator + 1);    

    // 获取组结点    
    XmlNode groupNode = rootMap.SelectSingleNode(group);    

    // 如果组结点不存在,创建之    
    if (groupNode == null) {    
       lock (this) {    
           groupNode = CreateNode(group);    
       }    
    }    

    // 创建一个唯一的 key ,用来映射 Xml 和对象的主键    
    string key = Guid.NewGuid().ToString();    

    // 创建一个新结点    
    XmlElement objectElement = rootMap.OwnerDocument.CreateElement(element);    

    // 创建结点属性 key    
    XmlAttribute objectAttribute = rootMap.OwnerDocument.CreateAttribute("key");    

    // 设置属性值为 刚才生成的 Guid    
    objectAttribute.Value = key;    

    // 将属性添加到结点    
    objectElement.Attributes.Append(objectAttribute);    

    // 将结点添加到 groupNode 下面(groupNode为Xpath的层次部分)    
    groupNode.AppendChild(objectElement);    

    // 将 key 和 对象添加到实际的存储位置,比如Hashtable    
    cacheStrategy.AddItem(key, obj);    
}

RemoveItem()则用于从缓存中删除对象,它也包含了两个步骤:1、先从Xml文档树中删除结点;2、再从实际的存储位置(Hashtable)中删除对象。这里需要注意的是:如果XPath指定的是一个叶结点,那么直接删除该结点;如果XPath指定的是组结点,那么需要删除组结点下的所有结点。代码如下: 
C#复制代码
// 根据 XPath 删除对象    
public virtual void RemoveItem(string xpath) {    

    xpath = PrepareXPath(xpath);    
    XmlNode result = rootMap.SelectSingleNode(xpath);    

    string key;           // 对象的Id     

    // 如果 result 是一个组结点(含有子结点)    
    if (result.HasChildNodes) {    

       // 选择所有包含有key属性的的结点    
       XmlNodeList nodeList = result.SelectNodes("descendant::*[@key]");    

       foreach (XmlNode node in nodeList) {    

           key = node.Attributes["key"].Value;    

           // 从 Xml 文档中删除结点    
           node.ParentNode.RemoveChild(node);    

           // 从实际存储中删除结点    
           cacheStrategy.RemoveItem(key);    
       }    
    } else {      // 如果 result 是一个叶结点(不含子结点)    

       key = result.Attributes["key"].Value;    
       result.ParentNode.RemoveChild(result);    
       cacheStrategy.RemoveItem(key);    
    }    
}

相关文章

最新评论