C#开发微信门户及应用(48) - 在微信框架中整合CacheManager 缓存
?在我们的很多框架或者项目应用中,缓存在一定程度上可以提高程序的响应速度,以及减轻服务器的承载压力,因此在一些地方我们都考虑引入缓存模块,这篇随笔介绍使用开源缓存框架CacheManager来实现数据的缓存,在微信开发框架中,我们有一些常用的处理也需要应用到缓存,因此本随笔以微信框架为例介绍缓存的实际使用,实际上,在我们很多框架中,如混合式开发框架、Web开发框架、Bootstrap开发框架中,这个模块都是通用的。 1、框架的缓存设计在我们的微信开发框架中,缓存作为数据库和对外接口之间的一个分层,提供数据的缓存响应处理,如下结构所示是Web?API层对缓存的架构设计。 在缓存的处理中,我侧重于使用CacheManager,这个缓存框架是一个集大成者,关于CacheManager?的介绍,我们可以回顾下我之前的随笔《》。 CacheManager是一个以C#语言开发的开源.Net缓存框架抽象层。它不是具体的缓存实现,但它支持多种缓存提供者(如Redis、Memcached等)并提供很多高级特性。CacheManager 主要的目的使开发者更容易处理各种复杂的缓存场景,使用CacheManager可以实现多层的缓存,让进程内缓存在分布式缓存之前,且仅需几行代码来处理。CacheManager 不仅仅是一个接口去统一不同缓存提供者的编程模型,它使我们在一个项目里面改变缓存策略变得非常容易,同时也提供更多的特性:如缓存同步、并发更新、序列号、事件处理、性能计算等等,开发人员可以在需要的时候选择这些特性。 CacheManager的GitHub源码地址为:,如果需要具体的Demo及说明,可以访问其官网: 2、在微信框架中整合CacheManager 缓存框架在使用CacheManager?缓存的时候,我们可以直接使用相关对象进行处理,首先需要定义一个类来进行初始化缓存的设置,然后进行调用,调用的时候可以使用IOC的方式构建对象,如下代码所示创建一个自定义的缓存管理类
ICacheManager<> Manager { ;
</span><span style="color: #808080;">///</span> <span style="color: #808080;"><summary></span>
<span style="color: #808080;">///</span><span style="color: #008000;"> 默认构造函数
</span><span style="color: #808080;">///</span> <span style="color: #808080;"></summary></span>
<span style="color: #0000ff;">public</span><span style="color: #000000;"> CacheManager()
{
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 初始化缓存管理器</span>
Manager = CacheFactory.Build(<span style="color: #800000;">"</span><span style="color: #800000;">getStartedCache</span><span style="color: #800000;">"</span>,settings =><span style="color: #000000;">
{
settings
.WithSystemRuntimeCacheHandle(</span><span style="color: #800000;">"</span><span style="color: #800000;">handleName</span><span style="color: #800000;">"</span><span style="color: #000000;">)
.And
.WithRedisConfiguration(</span><span style="color: #800000;">"</span><span style="color: #800000;">redis</span><span style="color: #800000;">"</span>,config =><span style="color: #000000;">
{
config.WithAllowAdmin()
.WithDatabase(</span><span style="color: #800080;">0</span><span style="color: #000000;">)
.WithEndpoint(</span><span style="color: #800000;">"</span><span style="color: #800000;">localhost</span><span style="color: #800000;">"</span>,<span style="color: #800080;">6379</span><span style="color: #000000;">);
})
.WithMaxRetries(</span><span style="color: #800080;">100</span><span style="color: #000000;">)
.WithRetryTimeout(</span><span style="color: #800080;">50</span><span style="color: #000000;">)
.WithRedisBackplane(</span><span style="color: #800000;">"</span><span style="color: #800000;">redis</span><span style="color: #800000;">"</span><span style="color: #000000;">)
.WithRedisCacheHandle(</span><span style="color: #800000;">"</span><span style="color: #800000;">redis</span><span style="color: #800000;">"</span>,<span style="color: #0000ff;">true</span><span style="color: #000000;">)
;
});
}
}
} 然后在Autofac的配置文件中配置缓存的相关信息,如下文件所示。 如果直接使用Autofac的构造类来处理,那么调用缓存处理的代码如下所示。
cache = AutoFactory.Instatnce.Container.Resolve
accountInfo </span>= cache.Manager.Get(key) <span style="color: #0000ff;">as</span><span style="color: #000000;"> AccountInfo;
}
} </span></pre>
如果为了使用方便,我们还可以对这个辅助类进行进一步的封装,以便对它进行统一的调用处理即可。
locker =
</span><span style="color: #808080;">///</span> <span style="color: #808080;"><summary></span>
<span style="color: #808080;">///</span><span style="color: #008000;"> 创建一个缓存的键值,并指定响应的时间范围,如果失效,则自动获取对应的值
</span><span style="color: #808080;">///</span> <span style="color: #808080;"></summary></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><typeparam name="T"></span><span style="color: #008000;">对象类型</span><span style="color: #808080;"></typeparam></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><param name="key"></span><span style="color: #008000;">对象的键</span><span style="color: #808080;"></param></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><param name="cachePopulate"></span><span style="color: #008000;">获取缓存值的操作</span><span style="color: #808080;"></param></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><param name="expiration"></span><span style="color: #008000;">失效的时间范围</span><span style="color: #808080;"></param></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><param name="mode"></span><span style="color: #008000;">失效类型</span><span style="color: #808080;"></param></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><returns></returns></span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> T GetCacheItem<T>(<span style="color: #0000ff;">string</span> key,Func<T><span style="color: #000000;"> cachePopulate,TimeSpan expiration,</span><span style="color: #0000ff;">string</span> region = <span style="color: #800000;">"</span><span style="color: #800000;">_</span><span style="color: #800000;">"</span>,ExpirationMode mode = ExpirationMode.Sliding) <span style="color: #0000ff;">where</span> T :<span style="color: #0000ff;">class</span><span style="color: #000000;">
{
CacheItem</span><<span style="color: #0000ff;">object</span>> outItem = <span style="color: #0000ff;">null</span><span style="color: #000000;">;
</span><span style="color: #008000;">//</span><span style="color: #008000;">通过AutoFac工厂获取对应的接口实现</span>
<span style="color: #0000ff;">var</span> cache = AutoFactory.Instatnce.Container.Resolve<ICacheManager><span style="color: #000000;">();
</span><span style="color: #0000ff;">if</span> (cache != <span style="color: #0000ff;">null</span><span style="color: #000000;">)
{
</span><span style="color: #0000ff;">if</span> (cache.Manager.Get(key,region) == <span style="color: #0000ff;">null</span><span style="color: #000000;">)
{
</span><span style="color: #0000ff;">lock</span><span style="color: #000000;"> (locker)
{
</span><span style="color: #0000ff;">if</span> (cache.Manager.Get(key,region) == <span style="color: #0000ff;">null</span><span style="color: #000000;">)
{
</span><span style="color: #008000;">//</span><span style="color: #008000;">Add、Put差异,Add只有在空值的情况下执行加入并返回true,Put总会替换并返回True
</span><span style="color: #008000;">//</span><span style="color: #008000;">如果按下面的方式加入,那么会留下历史丢弃的键值: cache.Manager.Put(key,value);</span>
<span style="color: #0000ff;">var</span> value =<span style="color: #000000;"> cachePopulate();
</span><span style="color: #0000ff;">var</span> item = <span style="color: #0000ff;">new</span> CacheItem<<span style="color: #0000ff;">object</span>><span style="color: #000000;">(key,region,mode,expiration);
cache.Manager.Put(item);
}
}
}
</span><span style="color: #0000ff;">return</span> cache.Manager.Get(key,region) <span style="color: #0000ff;">as</span><span style="color: #000000;"> T;
}
</span><span style="color: #0000ff;">else</span><span style="color: #000000;">
{
</span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> ArgumentNullException(<span style="color: #800000;">"</span><span style="color: #800000;">AutoFac配置参数错误,请检查autofac.config是否存在ICacheManager的定义</span><span style="color: #800000;">"</span><span style="color: #000000;">);
}
}
}</span></pre>
不过由于官方已经提供了一个类似上面的代码逻辑的TryGetOrAdd方法,这个方法的定义如下所示。 ,out TCacheValue)Tries to either retrieve an existing item or add the item to the cache if it does not exist. The?
valueFactory,
cache.Manager.TryGetOrAdd(key,(_key,_region) => value = item = CacheItem<> outItem T;
整个类的代码如下所示
T GetCacheItem
这样代码就简化了不少,而且不用自己控制读取的线程锁了,下面代码是使用辅助类实现缓存的添加及获取处理。
AccountInfo GetAccountByID(=
</span><span style="color: #0000ff;">#region</span> 使用.NET CacheManager缓存
<span style="color: #008000;">//</span><span style="color: #008000;">正常情况下access_token有效期为7200秒,这里使用缓存设置短于这个时间即可</span>
<span style="color: #0000ff;">var</span> key = <span style="color: #800000;">"</span><span style="color: #800000;">GetAccountByID_</span><span style="color: #800000;">"</span> +<span style="color: #000000;"> accountId;
accountInfo </span>= CacheManagerHelper.GetCacheItem<AccountInfo>(key,() =><span style="color: #000000;">
{
</span><span style="color: #0000ff;">return</span> BLLFactory<Account><span style="color: #000000;">.Instance.FindByID(accountId);
},TimeSpan.FromMinutes(TimeOut_Minutes));
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> accountInfo;
}</span></pre>
通过这样的辅助类封装,我们可以在需要缓存的函数里面,统一使用辅助类对数据进行缓存或者读取缓存的操作。 我们也可以直接使用Autofac构建的缓存管理进行操作,如在小程序里面,我们对用户敏感数据的解密处理函数,如下所示。
SmallAppUserInfo Decrypt( encryptedData, iv,= </span><span style="color: #008000;">//</span><span style="color: #008000;">通过AutoFac工厂获取对应的接口实现</span>
<span style="color: #0000ff;">var</span> cache = AutoFactory.Instatnce.Container.Resolve<ICacheManager><span style="color: #000000;">();
</span><span style="color: #0000ff;">if</span> (cache != <span style="color: #0000ff;">null</span><span style="color: #000000;">)
{
</span><span style="color: #008000;">//</span><span style="color: #008000;">从缓存里面,获取对应的SessionKey</span>
<span style="color: #0000ff;">var</span> sessionkey =<span style="color: #000000;"> cache.Manager.Get(thirdkey);
</span><span style="color: #0000ff;">if</span> (sessionkey != <span style="color: #0000ff;">null</span><span style="color: #000000;">)
{
</span><span style="color: #008000;">//</span><span style="color: #008000;">对用户身份加密数据进行解析,获取包含openid等属性的完整对象</span>
IBasicApi api = <span style="color: #0000ff;">new</span><span style="color: #000000;"> BasicApi();
userInfo </span>=<span style="color: #000000;"> api.Decrypt(encryptedData,iv,sessionkey.ToString());
}
}
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> userInfo;
}</span></pre>
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |