Enterprise Library 缓存应用程序块的设计
缓存应用程序为以下目的而设计:
-
提供一个大小可管理的 API 集合。
-
允许开发人员添加标准的缓存操作到他们的应用程序中,而不用学习应用程序块的内部工作。
-
用 Enterprise Library 配置控制台来简化配置。
-
有效率的执行。
-
线程安全。某些东西在被多个程序线程调用而没有属于那些线程的不必要的交互时,它被视为是线程安全的。
-
如果在访问后端存储时发生异常,确保后端存储依然是完整的。
-
保存内存缓存的状态与后端存储保持同步。
设计亮点
图1说明了缓存应用程序块中关键类的相互关系。
当使用 CacheFactory
初始化一个
CacheManager
的实例时,它在内部创建了一个
CacheManagerFactory
对象,然后创建一个Cache
对象。在 Cache
对象被创建后,所有在后端存储中的数据被加载到一个包含中 Cahce
对象的内存表示中。然后应用程序就可以向 CacheManager
对象发出请求以获取缓存的数据、添加数据到缓存以及从缓存中移除数据。
当应用程序使用 Add
方法发送一个请求到
CacheManager
对象以添加条目到缓存中时,CacheManager
对象又将请求发送给 Cache
对象。如果已存在同样键的的条目,Cache
对象会在添加新条目到内存缓存和后端存储之前删除它。如果后端存储是默认的
NullBackingStore
,数据将仅写到内存中。如果在条目添加时已缓存条目的数量已超出了预设的限制,BackgroundScheduler
对象将开始清理。在添加条目时,应用程序可以使用 Add
方法的一个重载来指定一个过期策略数组、清理优先级,以及一个实现了
ICacheItemRefreshAction
接口的对象。
当添加的条目没有在内存哈希表中时,Cache
对象首先创建一个模型缓存条目并将它添加到内存哈希表中。然后锁定内存哈希表中的条目,添加条目到后端存储中,最后用新的缓存条目替换掉在内存哈希表中的条目。(在条目已存在于内存哈希表中的情况下,它替换模型条目。)如果在写入后端存储时发生了异常,它会移除添加到内存哈希表中的模型条目且不再继续。缓存应用程序块强制了一个强壮的异常安全保证。这意味着,如果
Add
操作失败,缓存的状态将回滚到尝试添加条目以前的状态。换句话说,操作要么完全成功,要么缓存的状态保持不变。(这也同样适用于
Remove
和 Flush
方法。)
BackgroundScheduler
对象周期性的监视缓存中条目的生命期。当条目过期时,BackgroundScheduler
对象首先移除它,然后可能通知应用程序条目已被移除。此时,应用程序的响应时刷新缓存。
详细设计
CacheManager
类是缓存应用程序块其余部分和应用程序之间的接口,所有的操作都通过此类。对于使用没有修改过的应用程序块的开发人员,CacheManager
对象提供了所有添加、获取和从缓存中移除条目的所需方法。通过 CacheManager
对象调用的所有方法都是线程安全的。
要创建 CacheManager
对象实例,应用程序要使用
CacheFactory
类,然后使用 CacheManagerFactory
类。CacheManagerFactory
类创建所有实现
CacheManager
所需要的内部类。
每个名称只能用于一个缓存,要创建多个缓存的实例,就得使用多个名称。要注意的是,不同的缓存,也就是不同名称的缓存,不能共享同样的后端存储。每个
CacheManager
对象也仅有一个后端存储。
Cache
对象接收来自
CacheManager
对象的请求,并实现所有缓存数据的后端存储和内存表示之间的操作。它包含一个保存数据内存表示的哈希表。( 这是用户看到的格式。)一个数据条目被包装成一个
CacheItem
对象,此对象包含了数据本身,以及如条目的键、优先级、RefreshAction
对象和过期策略(或策略数组)等其他信息。它被存储在哈希表中。Cache
对象还使用一个同步的哈希表来控制应用程序和 BackgroundScheduler
对缓存中条目的访问。Cache
对象为整个缓存应用程序块提供了线程安全。
BackgroundScheduler
对象的职责是终止过期的缓存条目和清理低优先级的缓存条目。一个 PollTimer
对象会触发过期周期,以及一个数量限制会触发清理进程,这些都在配置文件中进行设置。
BackgroundScheduler
对象是主动对象模式( Active Object
Pattern )的一个实现。这意味着与 BackgroundScheduler
对象会话的其他对象(在此是 PollTimer
)就像已存在于调用对象的线程中。在它被调用后,BackgroundScheduler
将请求打包成一条消息,并将它放到一个队列集合对象中,而不是马上执行所请求的行为。(记住,这都发生在调用者的线程中。)这个队列是生产者/消费者(Produceer-Consumer)模式的一个示例。当BackgoundScheduler
处理完消息时,一个内部线程将从队列中取出消息。实际上,BackgoundScheduler
串行化了所有清理和到期请求。
对于它自己的线程,BackgroundScheduler
对象按顺序从队列中移除消息,然后执行请求。对于到期过程,它调用ExpirationTimeoutExpiredMsg
类的 Run
方法。对于清理过程,它调用
StartScavengingMsg
类的 Run
方法。在一个单一线程中顺序执行操作的好处是保证代码运行在单一线程的环境中,这使代码和它的影响更容易理解。
包含在缓存应用程序块中的缓存存储类是 DataBackingStore
类、IsolatedStorageBackingStore
类和
NullBackingStore
类。如果有兴趣开始自己的后端存储,你的类必须实现
IBackingStore
接口,或者从实现了 IBackingStore
接口的抽象类 BaseBackingStore
继承。
此类包含了普通策略的实现和可以用于所有后端存储的实用方法。
DataBackingStore
类在后端存储是数据访问应用程序块时被使用。用配置控制台配置它使用一个命名的数据库实例。IsolatedSorageBackingStore
类在特定域隔离的存储中存储缓存条目。用配置控制台可以配置它使用一个命名的独立存储。缓存应用程序块通过
IBackingStore
接口与所有的后端存储隔离。
DataBackingStore
和
IsolatedStorageBackingStore
类可以在持久存储前加密缓存条目数据。缓存条目数据的加密可以通过配置使其可用。使用配置控制台,缓存存储可以配置为使用命名的对象加密算法提供程序。命名的提供程序也可以在用条目数据组装缓存之前从缓存存储中读取数据,解密数据时使用。