采用EntLib5.0(Unity+Interception+Caching)实现项目中可用的Caching机制
看了园子里很多介绍Caching的文章,多数都只介绍基本机制,对于Cache更新和依赖部分,更是只简单的实现ICacheItemRefreshAction接口,这在实际项目中是远远不够的。实际项目中,至少应该考虑以下3点:
- 外部数据:通过外部服务,从其他系统取来的数据。我们无法控制,也不知道啥时候会被更新。对于这部分数据,我们采用定时更新的策略,默认1小时更新1次,可配置。
- 内部数据:系统自己产生的数据,可以完全掌控。对这部分数据,我们实现ICacheItemRefreshAction接口,一旦失效,立即重取。
- 内部数据如何触发更新:具体哪些操作会触发哪个cache失效,例如Add/Delete/Update[User][s]->Get[User][s]失效,这种策略应该可以配置。
接下去分别展开。
0、前言
下面的讨论分成2大块,一是环境的搭建,包括用Unity提供服务实例+用Unity提供Interception。经过这一块,就可以AOP的方式实现Caching了,这部分园子里的文章很多,我简略的过一下。二是Caching的实现,分别从外部数据缓存+内部缓存+内部触发更新3部分来讨论。
1、环境的搭建
1.1、用Unity提供服务实例
这部分其实就是用Unity实现IInstanceProvider,再配合IEndpointBehavior之类的,来实现WCF与Unity的集成。核心代码如下:
public class UnityInstanceProvider : IInstanceProvider{
public object GetInstance(InstanceContext context, Message msg){
return UnityWrapper.Instance.Resolve(serviceType);
}
}
具体可参见Artech的这篇《WCF后续之旅(7):通过WCF Extension实现和Enterprise Library Unity Container的集成》。
1.2、用Unity提供Interception(即PIAB,PolicyInjection)
这里要先吐槽一下EntLib,向后的兼容性做的太差了,完全不符合微软一贯的风格。每出一个大版本就一堆Breaking Changes和Deprecated,真心有点郁闷。当然估计他们也有苦衷,比如EntLib6里的Caching,被包含到Net40里了,确实也只能放弃。好吧,回归正题。好在EntLib自带的帮助文档写的非常详尽,有问题应该优先去Manual里查看相关内容。
EntLib4.1的PIAB模块,到EntLib5里就完全基于Unity的Interception来实现了,到EntLib6里就干脆取消了。这里我们采用EntLib5里的配置来实现策略注入,核心配置如下:
<unity>
<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration"/>
<assembly name="Service"/>
<namespace name="Service"/>
<alias alias="CachingCallHandler" type="Service.Unity.CachingCallHandler, Service"/>
<container name="UnityContainer">
<extension type="Interception" />
<interception>
<policy name="caching">
<matchingRule name="allServiceMatch" type="NamespaceMatchingRule">
<constructor>
<param name="namespaceName" value="Service"/>
</constructor>
</matchingRule>
<callHandler name="cachingService" type="CachingCallHandler"/>
</policy>
</interception>
<register type="IService1">
<interceptor type="TransparentProxyInterceptor" />
<policyInjection />
</register>
</container>
</unity>
这里有个细节,为了方便配置,1是可以用EntLib里自带的EntLibConfig.exe,2是在vs菜单->XML->架构里,添加UnityConfiguration20.xsd或者EnterpriseLibrary.Configuration.xsd,这样就有智能提示了。如果有EntLib的安装目录里找不到.xsd文件,可以用Everything搜一下。
2、Caching的实现
2.1、外部数据缓存
外部数据是我们不可控的数据,什么时候更新不确定。我们采取定时更新的策略,更新的频率主要取决于外部数据的变化频率,比如我们项目里依赖是外部的基础数据,变化较少,所以只需1小时甚至半天更新一次。
原本我以为AbsoluteTime是我想要的(注:SlidingTime是用户第一次命中Cache后,再滑动一段时间才过期),但通过ILSpy查看内部代码才知道,EntLib不是在一到期就自动触发ICacheItemRefreshAction接口的,而是在用户访问Cache的时候,再根据时间判断是否过期,如果过期再触发RefreshAction。代码如下:
namespace Microsoft.Practices.EnterpriseLibrary.Caching{
public class Cache{
public object GetData(string key){
if(cacheItem.HasExpired()){
this.inMemoryCache.Remove(key);
RefreshActionInvoker.InvokeRefreshAction(cacheItem, CacheItemRemovedReason.Expired, this.instrumentationProvider);
this.instrumentationProvider.FireCacheExpired(1L);
}}}}
这样的用户体验当然差了些,不能让用户享受到Caching的全部好处,我们改用Timer自动更新Cache,注意请使用System.Threading.Timer,而不是System.Timers.Timer。代码如下://我们用自定义的TimerCacheAttribute来标识这类方法
var atts = input.MethodBase.GetCustomAttributes(typeof(TimerCacheAttribute), false);
if(atts.Length > ){
RefreshTimerUtil.Instance[key] = new Timer(e => {
object[] args = e as object[];
if(args == null || args.Length != ) return; var tmpInput = args[] as IMethodInvocation;
var tmpNext = args[] as GetNextHandlerDelegate;
var tmpReturn = tmpNext()(tmpInput, tmpNext);
if(tmpReturn.Exception == null) {
CacheWrapper.Instance.Add(key, tmpReturn.ReturnValue);
}
},
new object[] { input, getNext },
TimeSpan.Zero,
new TimeSpan(, , ));
}
2.2、内部数据缓存
内部数据可以直截了当的插入Cache,然后就静静的等待增删改操作来把它置为过期。
CacheWrapper.Instance.Add(key, methodReturn.ReturnValue,
CacheItemPriority.Normal,
new CacheRefreshAction { Input = input, GetNext = getNext });
当然,要实现ICacheItemRefreshAction接口,代码如下:
[Serializable]
public class CacheRefreshAction : ICacheItemRefreshAction {
public IMethodInvocation Input {get; set;}
public GetNextHandlerDelegate GetNext {get; set;}
public void Refresh(string removedKey, object expiredValue, CacheItemRemovedReason removalReason) {
if( Input == null || GetNext == null) return;
var methodReturn = GetNext()(Input, GetNext);
if(methodReturn.Exception == null) {
CacheWrapper.Instance.Add(removedKey, methodReturn.ReturnValue,
CacheItemPriority.Normal,
new CacheRefreshAction { Input = Input, GetNext = GetNext });
}
}
}
据说MemoryCache是不需要实现ISerializable的,而其他Caching要么实现ISerializable、要么打[Serializable]标签。不过这种实现方式,IMethodInvocation和GetNextHandlerDelegate目测序列化都略麻烦,好在目前我们只用到MemoryCache,可以先不管,以后再突破。
2.3、内部数据触发更新
最后就剩触发更新了,如何实现类似Add/Delete/Update[User][s]->Get[User][s]的效果呢?大致思路是:1)判断方法名里是否StartWith关键字(Add/Delete/Update);2)截取出目标关键字User、并生成对应的复数形式Users;3)与Get等动作拼接成CacheKey,把所有命中的CacheKey置为过期(CacheManager.Remove),即可触发对应的RefreshAction。代码如下:
var entity = string.Empty;
foreach (var act in ConfigUtil.Action){
if(methodName.StartsWith(act)) {
entity = methodName.Substring(act.Length);
break;
}} var entities = PluralUtil.Pluralize(entity);
if(entities == entity) entities = PluralUtil.Singularize(entity);
foreach (var prefix in ConfigUtil.Prefix) {
CacheWrapper.Instance.RemoveStartWith(prefix + entity);
CacheWrapper.Instance.RemoveStartWith(prefix + entities);
}
这里的产生单复数的代码是从EntityFramework里借来的,具体请查看EnglishPluralizationService。
如果有不正确的地方,欢迎批评指正!
采用EntLib5.0(Unity+Interception+Caching)实现项目中可用的Caching机制的更多相关文章
- .NET Core 3.0或3.1 类库项目中引用 Microsoft.AspNetCore.App
本文为原创文章.首发:http://www.zyiz.net/ 在 ASP.NET Core 3.0+ web 项目中已经不需要在 .csproj 中添加对 Microsoft.AspNetCore. ...
- 分享我们项目中基于EF事务机制的架构
写在前面: 1. 本文中单元测试用到的数据库,在执行测试之前,会被清空,即使用空数据库. 2. 本文中的单元测试都是正确通过的. 要理解EF的事务机制,首先要理解这2个类:TransactionSco ...
- 分享我们项目中基于EF事务机制的架构 【转载】
http://www.cnblogs.com/leotsai/p/how-to-use-entity-framework-transaction-scope.html 写在前面: 1. 本文中单元测试 ...
- Python:Django 项目中可用的各种装备和辅助
1 Redis 数据库 2 MySQL 数据库 3 前端服务器 live-server 4 定时任务 django-crontab扩展 5 Docker 容器 --用来运行 FastDFS 分布式文件 ...
- DotNet项目中的一些常用验证操作
在项目中需要对用户输入的信息,以及一些方法生成的结果进行验证,一般在项目中较多的采用js插件或js来进行有关信息的校验,但是从项目安全性的角度进行考虑,可对系统进行js注入. 如果在后台对用户输入的信 ...
- 在 ASP.NET Core 项目中使用 npm 管理你的前端组件包
一.前言 在项目的前端开发中,对于绝大多数的小伙伴来说,当然,也包括我,不可避免的需要在项目中使用到一些第三方的组件包.这时,团队中的小伙伴是选择直接去组件的官网上下载,还是图省事直接在网上搜索,然后 ...
- 如何在Crystal框架项目中内置启动MetaQ服务?
当Crystal框架项目中需要使用消息机制,而项目规模不大.性能要求不高时,可内置启动MetaQ服务器. 分步指南 项目引入crystal-extend-metaq模块,如下: <depende ...
- 1-跑Faster R-CNN项目中的一些问题
原理介绍: https://blog.csdn.net/quincuntial/article/details/79132243 我用的环境: Python 3.5.2 cpu版的ten ...
- java项目中常见的异常及处理
Java开发中常见异常及处理方法 1.JAVA异常 异常指不期而至的各种状况,如:文件找不到.网络连接失败.非法参数等.异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程.Java通 过API ...
随机推荐
- adb 查看日志信息
adb logcat 详解 (1) 下面命令将只会显示AndroidRuntime类型的Error消息: adb logcat -s AndroidRuntime (2) 显示全 ...
- java的IO流
java的IO流继承四大抽象类分别是字节流 inputStream outputStream与字符流 read write.怎么理解记忆很重要. 直接连接读写对象的是结点流,例如对文件读取字节类的名字 ...
- 10款实用Android UI 开发框架
1. ActionBarSherlock ActionBarSherlock是一个独立的Android设计库,可以让Android 2.x的系统也能使用ActionBar.此外,ActionBarSh ...
- Spring事务的传播特性和隔离级别
事务的几种传播特性1. PROPAGATION_REQUIRED: 如果存在一个事务,则支持当前事务.如果没有事务则开启2. PROPAGATION_SUPPORTS: 如果存在一个事务,支持当前事务 ...
- 杂谈:Servlet(2)
Servlet的方法剖析: 1.service()方法里面做了什么? 2.doGet()与doPost()做了什么?应该怎么写? 回答 1.service()方法里面做了什么? 如果你的service ...
- iOS 中对 HTTPS 证书链的验证
这篇文章是我一边学习证书验证一边记录的内容,稍微整理了下,共扯了三部分内容: HTTPS 简要原理: 数字证书的内容.生成及验证: iOS 上对证书链的验证. HTTPS 概要 HTTPS 是运行在 ...
- 5月5日 while、do{}while
while .do{}while 一.while的死循环 while (1 == 1)//只要表达式里是true,就是死循环 { //循环内容 } 二.do{}while 不管while是否满足,首先 ...
- Swing——JFrame
1.定义 相对于AWT(hevay weight component),Swing(hevay weight component)是轻量化的组件.Swing由纯Java Code 所写,解决了Java ...
- [转]JavaSE 8—新的时间和日期API
为什么我们需要一个新的时间日期API Java开发中一直存在一个问题,JDK提供的时间日期API一直对开发者没有提供良好的支持. 比如,已有的的类(如java.util.Date和SimpleDate ...
- Hyper-V和Virtual PC的不同
微软在2003年收购了推出了Virtual PC软件的Connectix公司,并在其后推出了Virtual Server服务器虚拟化软件 Hyper-V跟微软自家的Virtual PC.Virtual ...