缓存工厂之 Redis 缓存
ldf520cxf
8年前
<p>正式分享今天的文章吧:</p> <ul> <li> <p>搭建Redis服务端,并用客户端连接</p> </li> <li> <p>封装缓存父类,定义Get,Set等常用方法</p> </li> <li> <p>定义RedisCache缓存类,执行Redis的Get,Set方法</p> </li> <li> <p>构造出缓存工厂调用方法</p> </li> </ul> <p>下面一步一个脚印的来分享:</p> <p>搭建Redis服务端,并用客户端连接 首先,咋们去这个地址下载安装文件https://github.com/dmajkic/redis/downloads,我这里的版本是:redis-2.4.5-win32-win64里面有32位和64位的执行文件,我这里服务器是64位的下面给出截图和用到部分程序的说明:</p> <p><img src="https://simg.open-open.com/show/c1e28da7a89f34b13e54baeb6c7d3e0f.png"></p> <p>现在,咋们直接可以用鼠标双击redis-server.exe这个应用程序,这样就打开了redis服务窗体(您也可以下载一个windows服务承载器,把redis服务运行在windows的服务中,就不用担心每次关闭redis服务黑色窗体后无法访问redis了),运行起来是这样:</p> <p><img src="https://simg.open-open.com/show/64940f8d7a14d58e75de5ac717e58e18.png"></p> <p>有红色框的信息就表示成功了,这里redis服务监听的端口默认是6379,要修改端口或者更多的配置信息请找到redis.conf配置文件,具体配置信息介绍可以来这里http://www.shouce.ren/api/view/a/6231</p> <p>再来,打开客户端连接服务端,咋们退到64bit文件夹的目录中,鼠标移到64bit文件夹上并且安装Shift键,同时点击鼠标的右键,选中"在此处打开命令窗口"这样快速进入到了该文件夹的cmd命令窗口中(当然不同的操作系统不同,这里演示的是windows的操作;</p> <p>还有其他进入的方式这里不做介绍,因为个人感觉这是最快的);然后,在命令窗口中录入redis-cli.exe -h localhost -p 6379回车来访问服务端,效果图:</p> <p><img src="https://simg.open-open.com/show/723541d3acf8686abde7c91fe1a4b788.png"></p> <p>再来看下服务端窗体截图:</p> <p><img src="https://simg.open-open.com/show/0cc7a6bd4b67d70cd12ab5c468c8eb8b.png"></p> <p>没错这样客户端就连接上服务端了,可以简单在客户端执行下set,get命令:</p> <p><img src="https://simg.open-open.com/show/84a612c816cff54a6216cf2faf91eb12.png"></p> <p>如果是客户端要访问远程的redis服务端,只需要把localhost换成可访问的ip就行了如果还需要密码等更多配置请去上面的那个地址链接;</p> <p>封装缓存父类,定义Get,Set等常用方法</p> <p>先来,上父类的代码:</p> <pre> <code class="language-java">public class BaseCache : IDisposable { protected string def_ip = string.Empty; protected int def_port = 0; protected string def_password = string.Empty; public BaseCache() { } public virtual void InitCache(string ip = "", int port = 0, string password = "") { } public virtual bool SetCache<T>(string key, T t, int timeOutMinute = 10) where T : class,new() { return false; } public virtual T GetCache<T>(string key) where T : class,new() { return default(T); } public virtual bool Remove(string key) { return false; } public virtual bool FlushAll() { return false; } public virtual bool Any(string key) { return false; } public virtual void Dispose(bool isfalse) { if (isfalse) { } } //手动释放 public void Dispose() { this.Dispose(true); //不自动释放 GC.SuppressFinalize(this); } }</code></pre> <p>这里定义的方法没有太多的注释,更多的意思我想看方法名称就明白了,这个父类主要实现了IDisposable,实现的Dispose()中主要用来释放资源并且自定义了一个 public virtual void Dispose(bool isfalse)方法</p> <p>这里面有一句是GC.SuppressFinalize(this);按照官网介绍的意思是阻塞自动释放资源,其他的没有什么了,继续看下面的</p> <p>定义RedisCache缓存类,执行Redis的Get,Set方法。 首先,咋们分别定义类RedisCache,MemcachedCache(这里暂未实现对memcache缓存的操作),并且继承BaseCache,重写Set,Get方法如下代码:</p> <pre> <code class="language-java">/// <summary> /// Redis缓存 /// </summary> public class RedisCache : BaseCache { public RedisClient redis = null; public RedisCache() { //这里去读取默认配置文件数据 def_ip = "172.0.0.1"; def_port = 6379; def_password = ""; } #region Redis缓存 public override void InitCache(string ip = "", int port = 0, string password = "") { if (redis == null) { ip = string.IsNullOrEmpty(ip) ? def_ip : ip; port = port == 0 ? def_port : port; password = string.IsNullOrEmpty(password) ? def_password : password; redis = new RedisClient(ip, port, password); } } public override bool SetCache<T>(string key, T t, int timeOutMinute = 10) { var isfalse = false; try { if (string.IsNullOrEmpty(key)) { return isfalse; } InitCache(); isfalse = redis.Set<T>(key, t, TimeSpan.FromMinutes(timeOutMinute)); } catch (Exception ex) { } finally { this.Dispose(); } return isfalse; } public override T GetCache<T>(string key) { var t = default(T); try { if (string.IsNullOrEmpty(key)) { return t; } InitCache(); t = redis.Get<T>(key); } catch (Exception ex) { } finally { this.Dispose(); } return t; } public override bool Remove(string key) { var isfalse = false; try { if (string.IsNullOrEmpty(key)) { return isfalse; } InitCache(); isfalse = redis.Remove(key); } catch (Exception ex) { } finally { this.Dispose(); } return isfalse; } public override void Dispose(bool isfalse) { if (isfalse && redis != null) { redis.Dispose(); redis = null; } } #endregion } /// <summary> /// Memcached缓存 /// </summary> public class MemcachedCache : BaseCache { }</code></pre> <p>这里,用到的RedisClient类是来自nuget包引用的,这里nuget包是:</p> <p><img src="https://simg.open-open.com/show/d4201a045a8ccda9cfce0e40e31c74d7.png"></p> <p>然后,来看下重写的InitCache方法,这里面有一些ip,port(端口),password(密码)参数,这里直接写入在cs文件中没有从配置文件读取,大家可以扩展下;</p> <p>这些参数通过RedisClient构造函数传递给底层Socket访问需要的信息,下面简单展示下RedisClient几个的构造函数:</p> <pre> <code class="language-java">public RedisClient(); public RedisClient(RedisEndpoint config); public RedisClient(string host); public RedisClient(Uri uri); public RedisClient(string host, int port); public RedisClient(string host, int port, string password = null, long db = 0);</code></pre> <p>至于Get,Set方法最终都是使用RedisClient对象访问的,个人觉得需要注意的是Set方法里面的过期时间参数,目前还没有试验这种情况的效果:</p> <p>通过这几种方法设置过期时间后,快到过期时间的时候如果此时有使用这个缓存key那么过期时间是否会往后自动增加过期时间有效期,这里暂时没有试验(这里是由于前面项目中的.net core框架中的memecache缓存都有这种设置,想来redis应该也有吧)</p> <p>这里,需要重写下public override void Dispose(bool isfalse)方法,因为调用完RedisClient后需要释放,我们通过Dispose统一来手动释放,而不是直接在调用的时候使用using()</p> <p>构造出缓存工厂调用方法</p> <p>接下来,咋们需要定义一个缓存工厂,因为上面刚才定义了一个RedisCache和MemcachedCache明显这里会有多个不同缓存的方法调用,所用咋们来定义个工厂模式来调用对应的缓存;</p> <p>这里的工厂模式没有使用直接显示创建</p> <p>new RedisCache(), new MemcachedCache()对象的方法,而是使用了反射的原理,创建对应的缓存对象;</p> <p>先来,定义个枚举,枚举里面的声明的名字要和咋们缓存类的名称相同,代码如下:</p> <pre> <code class="language-java">public enum CacheType { RedisCache, MemcachedCache } 再来,定义个工厂来CacheRepository(缓存工厂),并且定义方法Current如下代码: public static BaseCache Current(CacheType cacheType = CacheType.RedisCache) { var nspace = typeof(BaseCache); var fullName = nspace.FullName; var nowspace = fullName.Substring(0, fullName.LastIndexOf('.') + 1); return Assembly.GetExecutingAssembly().CreateInstance(nowspace + cacheType.ToString(), true) as BaseCache; }</code></pre> <p>通过传递枚举参数,来确定反射CreateInstance()方法需要用到的typeName参数,从而来定义需要访问的那个缓存对象,这里要注意的是加上了一个命名空间nowspace,因为缓存类可能和工厂类不是同一个命名空间,但是通常会和缓存基类是同命名空间所以在方法最开始的时候截取获取了缓存类需要的命名空间(这里看自身项目来定吧);</p> <p>Assembly.GetExecutingAssembly()这个是用来获取当前应用程序集的路径,这里就避免了咋们使用Assembly.Load()方法还需要传递程序集的路径地址了</p> <p>好了满上上面要求后,咋们可以在测试页面调用代码如:</p> <p>CacheRepository.Current(CacheType.RedisCache).SetCache<MoFlightSearchResponse>(keyData, value);就如此简单,咋们使用redis-cli.exe客户端来看下缓存起来的数据:</p> <p><img src="https://simg.open-open.com/show/0182f15e76c07ff15716b46b88821854.png"></p> <p>怎么样,您们的是什么效果呢,下面给出整体代码:</p> <pre> <code class="language-java">public enum CacheType { RedisCache, MemcachedCache } public class CacheRepository { public static BaseCache Current(CacheType cacheType = CacheType.RedisCache) { var nspace = typeof(BaseCache); var fullName = nspace.FullName; var nowspace = fullName.Substring(0, fullName.LastIndexOf('.') + 1); return Assembly.GetExecutingAssembly().CreateInstance(nowspace + cacheType.ToString(), true) as BaseCache; } } public class BaseCache : IDisposable { protected string def_ip = string.Empty; protected int def_port = 0; protected string def_password = string.Empty; public BaseCache() { } public virtual void InitCache(string ip = "", int port = 0, string password = "") { } public virtual bool SetCache<T>(string key, T t, int timeOutMinute = 10) where T : class,new() { return false; } public virtual T GetCache<T>(string key) where T : class,new() { return default(T); } public virtual bool Remove(string key) { return false; } public virtual bool FlushAll() { return false; } public virtual bool Any(string key) { return false; } public virtual void Dispose(bool isfalse) { if (isfalse) { } } //手动释放 public void Dispose() { this.Dispose(true); //不自动释放 GC.SuppressFinalize(this); } } /// <summary> /// Redis缓存 /// </summary> public class RedisCache : BaseCache { public RedisClient redis = null; public RedisCache() { //这里去读取默认配置文件数据 def_ip = "172.16.2.56"; def_port = 6379; def_password = ""; } #region Redis缓存 public override void InitCache(string ip = "", int port = 0, string password = "") { if (redis == null) { ip = string.IsNullOrEmpty(ip) ? def_ip : ip; port = port == 0 ? def_port : port; password = string.IsNullOrEmpty(password) ? def_password : password; redis = new RedisClient(ip, port, password); } } public override bool SetCache<T>(string key, T t, int timeOutMinute = 10) { var isfalse = false; try { if (string.IsNullOrEmpty(key)) { return isfalse; } InitCache(); isfalse = redis.Set<T>(key, t, TimeSpan.FromMinutes(timeOutMinute)); } catch (Exception ex) { } finally { this.Dispose(); } return isfalse; } public override T GetCache<T>(string key) { var t = default(T); try { if (string.IsNullOrEmpty(key)) { return t; } InitCache(); t = redis.Get<T>(key); } catch (Exception ex) { } finally { this.Dispose(); } return t; } public override bool Remove(string key) { var isfalse = false; try { if (string.IsNullOrEmpty(key)) { return isfalse; } InitCache(); isfalse = redis.Remove(key); } catch (Exception ex) { } finally { this.Dispose(); } return isfalse; } public override void Dispose(bool isfalse) { if (isfalse && redis != null) { redis.Dispose(); redis = null; } } #endregion } /// <summary> /// Memcached缓存 /// </summary> public class MemcachedCache : BaseCache { }</code></pre> <p>这次分享的Redis缓存从搭建到使用希望给您们有帮助,还请多多支持点赞,谢谢。</p> <p>【今日微信公号推荐↓】</p> <p><img src="https://simg.open-open.com/show/89626fc3d729ebeddac9989c75b9829e.jpg"></p> <p> </p> <p>来自:http://mp.weixin.qq.com/s?__biz=MzAxMTMxMDQ3Mw==&mid=2660099443&idx=2&sn=fa55cb05bd9c5f70f8f12b2a21a6f812&scene=0</p> <p></p> <p> </p> <p><span style="background:rgb(189, 8, 28) url("data:image/svg+xml; border-radius:2px; border:medium none; color:rgb(255, 255, 255); cursor:pointer; display:none; font:bold 11px/20px "Helvetica Neue",Helvetica,sans-serif; left:30px; opacity:0.85; padding:0px 4px 0px 0px; position:absolute; text-align:center; text-indent:20px; top:372px; width:auto; z-index:8675309">Save</span></p>