应用框架的设计与实现——.NET平台(5 缓存服务.源码分析)

来源:互联网 发布:公安大数据分析平台 编辑:程序博客网 时间:2024/06/05 14:59
缓存服务的功能:缓存服务可提高对象的重用性,减少读取数据库、计算等操作步骤;为此付出的代价是对象使用前的判断和对象存储内存空间的开销。

 作者对缓存服务的设计特点:基于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;
        }

    }


存储缓存对象的对象的接口:

    /// <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);
    }

缓存服务对象的实现依赖配置文件配置项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>

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];
        }

    }


使用缓存服务的代码 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();
        }

    }

}