1. MemoryCahe

NetCore中的缓存和System.Runtime.Caching很相似,但是在功能上做了增强,缓存的key支持object类型;提供了泛型支持;可以读缓存和单个缓存项的大小做限定,可以设置缓存的压缩比例。

通过实现微软官方的Microsoft.Extensions.Caching里面的IDistributedCache接口实现缓存集成到ASPNETCore中

1.1 简单入门

netcore中缓存相关的类库都在 Microsoft.Extensions.Caching ,使用MemoryCache首先安装包

<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" />

注入

        public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
//添加缓存配置
services.AddMemoryCache();
}

使用

        private readonly IMemoryCache _cache;
public HomeController(IMemoryCache cache)
{
_cache = cache;
} [HttpGet]
public string Set()
{
//写
_cache.Set("login", "4545478244");
return "";
} [HttpGet]
public string Get()
{
//读
var value = _cache.Get("login");
return "";
}

1.2 过期时间

            //1.最简单使用方式
_cache.Set("mykey", "myvalue");
//2.绝对过期时间,3秒后过期
_cache.Set("key1", "value1", new DateTimeOffset(DateTime.Now.AddSeconds(3)));
//3.绝对过期时间,效果同上
_cache.Set("key2", "value2", TimeSpan.FromSeconds(3));
//4.滑动过期时间,3秒后,即三秒钟内被访问,则重新刷新缓存时间为3秒后
_cache.Set("key3", "value3", new MemoryCacheEntryOptions
{
SlidingExpiration = TimeSpan.FromSeconds(3),
});
Console.WriteLine("-----------暂停2秒");
Thread.Sleep(2000);//暂停2秒
Console.WriteLine($"key1的值:{_cache.Get("key1") ?? "key1被清除"}");
Console.WriteLine($"key2的值:{_cache.Get("key2") ?? "key2被清除"}");
Console.WriteLine($"key3的值:{_cache.Get("key3") ?? "key3被清除"}");
Console.WriteLine("-----------暂停2秒");
Thread.Sleep(2000);//再次暂停2秒
Console.WriteLine($"key1的值:{_cache.Get("key1") ?? "key1被清除"}");
Console.WriteLine($"key2的值:{_cache.Get("key2") ?? "key2被清除"}");
Console.WriteLine($"key3的值:{_cache.Get("key3") ?? "key3被清除"}");

在例子中key1,key2都是使用的绝对过期时间,key3使用的相对过期时间,2秒后第一次访问key1、key2、key3都没过期,其中key3的过期时间刷新了,重新设置为3秒后,所以再次暂停2秒后,key1、key2都过期了,key3仍然存在。

程序运行结果如下:

1.2 常用配置

下边的例子介绍netcore中缓存的常用配置,直接看代码

        public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(); services.AddMemoryCache(options =>
{
//缓存大小
options.SizeLimit = 3;//如果设置了该值,那么每个set都必须设置size,并且超过了这个值的大小的会自动销毁
//缓存满了时,压缩20%(即删除20份优先级低的缓存项)
options.CompactionPercentage = 0.2;
//两秒钟查找一次过期项
options.ExpirationScanFrequency = TimeSpan.FromSeconds(3);
});
} [HttpGet]
public string TestSize()
{
//SizeLimit配置3
_cache.Set("item1", "11111", new MemoryCacheEntryOptions
{
//缓存大小占1份
Size = 2
});
_cache.Set("item2", "22222", new MemoryCacheEntryOptions
{
Size = 2
});
var item1 = _cache.Get("item1");//输出 11111
var item2 = _cache.Get("item2");//输出 null return "";
} [HttpGet]
public string TestOptions()
{
//单个缓存项的配置
MemoryCacheEntryOptions cacheEntityOps = new MemoryCacheEntryOptions()
{
//绝对过期时间1
//AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddSeconds(2)),
//绝对过期时间2
//AbsoluteExpirationRelativeToNow=TimeSpan.FromSeconds(3),
//相对过期时间
SlidingExpiration = TimeSpan.FromSeconds(3),
//优先级,当缓存压缩时会优先清除优先级低的缓存项
Priority = CacheItemPriority.Low,//优先级等级:Low,Normal,High,NeverRemove
//缓存大小占1份
Size = 1
};
//注册缓存项被清除时的回调,可以注册多个回调
cacheEntityOps.RegisterPostEvictionCallback((key, value, reason, state) =>
{
Console.WriteLine($"回调函数输出【键:{key},值:{value},被清除的原因:{reason}】");
});
_cache.Set("mykey", "myvalue", cacheEntityOps);
Console.WriteLine($"mykey的值:{_cache.Get("mykey") ?? "mykey缓存被清除了"}");
Console.WriteLine("------------------暂停3秒");
Thread.Sleep(3000);
Console.WriteLine($"mykey的值:{_cache.Get("mykey") ?? "mykey缓存被清除了"}"); return "";
}

注意netcore中设置缓存和缓存项大小是没有单位的

缓存被清空的回调函数可以注册多个(System.Runtime.Caching清除缓存的回调只能是一个)。

程序执行结果

1.3 IChangeToken

上边我们已经简单了解了通过滑动过期时间和绝对过期时间来控制缓存的有效性,但是有时缓存的过期与否和时间没有联系,比如我们缓存一个文件的内容,不管缓存多久只要文件没有发生变化缓存都是有效的。在net framework中我们可以通过CacheDependency来控制,在net core中怎么控制呢?net core中我们可以使用IChangeToken接口轻松实现缓存的过期策略。先看一下IChangeToken接口:

    public interface IChangeToken
{
// 是否有变化发生
bool HasChanged { get; }
// token是否会调用回调函数,为true时才会有效
bool ActiveChangeCallbacks { get; }
// 注册一个回调函数,当有变化时触发回调
IDisposable RegisterChangeCallback(Action<object> callback, object state);
}

看一下IChangeToken实现缓存过期策略的两个例子

1.3.1 监控文件

需要安装组件:Microsoft.Extensions.FileProviders.Physical

    internal class Program
{
private static void Main(string[] args)
{
string fileName = Path.Combine(Environment.CurrentDirectory, "someCacheData.xml");
var fileInfo = new FileInfo(fileName);
MemoryCache myCache = new MemoryCache(new MemoryCacheOptions() { });
MemoryCacheEntryOptions cacheEntityOps = new MemoryCacheEntryOptions();
//PollingFileChangeToken是IChangeToken的实现类,通过轮询监控文件变化
cacheEntityOps.AddExpirationToken(new Microsoft.Extensions.FileProviders.Physical.PollingFileChangeToken(fileInfo));
//缓存失效时,回调函数
cacheEntityOps.RegisterPostEvictionCallback((key, value, reason, state) => { Console.WriteLine($"文件【{key}】改动了"); });
//添加缓存,key为文件名,value为文件内容
myCache.Set(fileInfo.Name, File.ReadAllText(fileName), cacheEntityOps);
Console.WriteLine(myCache.Get(fileInfo.Name));
}
}

PollingFileChangeToken通过轮询来监控文件有没有发生变化,如果文件中的内容发生改变,缓存就会自动过期。

1.3.2 通过代码控制缓存过期

    class Program
{
static void Main(string[] args)
{
MemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions());
MemoryCacheEntryOptions cacheEntityOps = new MemoryCacheEntryOptions();
//使用CancellationChangeToken控制缓存过期
CancellationTokenSource tokenSource = new CancellationTokenSource();
cacheEntityOps.AddExpirationToken(new CancellationChangeToken(tokenSource.Token));
//设置缓存
memoryCache.Set("mykey", "myvalue", cacheEntityOps);
Console.WriteLine(memoryCache.Get("mykey") ?? "缓存被清除了");
//通过代码清除缓存
tokenSource.Cancel();
Console.WriteLine(memoryCache.Get("mykey") ?? "缓存被清除了");
}
}

tokenSource.Cancel方法发送取消信号,这个方法会触发缓存过期,基于此我们可以通过Cancel方法灵活的实现自定义的缓存策略。

程序执行结果如下:

1.4 引用Nuget包

直接引用我自己简单封装的一个Nuget包(简单封装自己用,不要嘲笑)

    <PackageReference Include="Common.Cache.MemoryCache" Version="1.1.0" />

注入到容器

        public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
//注入
services.AddMemoryCacheExtension();
}

使用

        # 在需要使用的地方进行注入
private readonly IMemoryCachimg _cache;
public HomeController(IMemoryCachimg cache)
{
_cache = cache;
}

参考文档

作者:捞月亮的猴子  https://www.cnblogs.com/wyy1234/p/10519681.html
官方教程:https://docs.microsoft.com/zh-cn/aspnet/core/performance/caching/memory?view=aspnetcore-5.0

微信公众号

.Net缓存之MemoryCahe的更多相关文章

  1. .Net Core缓存组件(Redis)源码解析

    上一篇文章已经介绍了MemoryCache,MemoryCache存储的数据类型是Object,也说了Redis支持五中数据类型的存储,但是微软的Redis缓存组件只实现了Hash类型的存储.在分析源 ...

  2. 探究javascript对象和数组的异同,及函数变量缓存技巧

    javascript中最经典也最受非议的一句话就是:javascript中一切皆是对象.这篇重点要提到的,就是任何jser都不陌生的Object和Array. 有段时间曾经很诧异,到底两种数据类型用来 ...

  3. 哪种缓存效果高?开源一个简单的缓存组件j2cache

    背景 现在的web系统已经越来越多的应用缓存技术,而且缓存技术确实是能实足的增强系统性能的.我在项目中也开始接触一些缓存的需求. 开始简单的就用jvm(java托管内存)来做缓存,这样对于单个应用服务 ...

  4. ASP.NET Core 中间件之压缩、缓存

    前言 今天给大家介绍一下在 ASP.NET Core 日常开发中用的比较多的两个中间件,它们都是出自于微软的 ASP.NET 团队,他们分别是 Microsoft.AspNetCore.Respons ...

  5. ASP.NET Core 折腾笔记二:自己写个完整的Cache缓存类来支持.NET Core

    背景: 1:.NET Core 已经没System.Web,也木有了HttpRuntime.Cache,因此,该空间下Cache也木有了. 2:.NET Core 有新的Memory Cache提供, ...

  6. [Java 缓存] Java Cache之 DCache的简单应用.

    前言 上次总结了下本地缓存Guava Cache的简单应用, 这次来继续说下项目中使用的DCache的简单使用. 这里分为几部分进行总结, 1)DCache介绍; 2)DCache配置及使用; 3)使 ...

  7. [原创]mybatis中整合ehcache缓存框架的使用

    mybatis整合ehcache缓存框架的使用 mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓 ...

  8. 探索ASP.NET MVC5系列之~~~5.缓存篇(页面缓存+二级缓存)

    其实任何资料里面的任何知识点都无所谓,都是不重要的,重要的是学习方法,自行摸索的过程(不妥之处欢迎指正) 汇总:http://www.cnblogs.com/dunitian/p/4822808.ht ...

  9. 深究标准IO的缓存

    前言 在最近看了APUE的标准IO部分之后感觉对标准IO的缓存太模糊,没有搞明白,APUE中关于缓存的部分一笔带过,没有深究缓存的实现原理,这样一本被吹上天的书为什么不讲透彻呢?今天早上爬起来赶紧找了 ...

  10. 缓存工厂之Redis缓存

    这几天没有按照计划分享技术博文,主要是去医院了,这里一想到在医院经历的种种,我真的有话要说:医院里的医务人员曾经被吹捧为美丽+和蔼+可亲的天使,在经受5天左右相互接触后不得不让感慨:遇见的有些人员在挂 ...

随机推荐

  1. 45从零开始用Rust编写nginx,静态文件服务器竟然还有这些细节

    wmproxy wmproxy已用Rust实现http/https代理,socks5代理, websocket代理,反向代理, 静态文件服务器,四层TCP/UDP转发,七层负载均衡,内网穿透等,力争打 ...

  2. React Hooks源码深度解析

    作者:京东零售 郑炳懿 前言 React Hooks是React16.8 引入的一个新特性,它允许函数组件中使用state和其他 React 特性,而不必使用类组件.Hooks是一个非常重要的概念,因 ...

  3. 【学到一个小技巧】context.WithValue 中的 key 可以是个空对象

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 从 netpoll 库看到这段代码: type connk ...

  4. 【Java 进阶】详细探究 Spring 框架中的注解与反射

    [进阶]Spring中的注解与反射 目录 [进阶]Spring中的注解与反射 前言 一.内置(常用)注解 1.1@Overrode 1.2@RequestMapping 1.3@RequestBody ...

  5. 【主流技术】实战之 Spring Boot 中集成微信支付(小程序)

    前言 微信支付是企业级项目中经常使用到的功能,作为后端开发人员,完整地掌握该技术是十分有必要的. 以下是经过真实商业项目实践的集成步骤,包括注册流程.调用过程.代码demo(经过脱敏)等,希望我的分享 ...

  6. 卧槽!这 5 个后端程序员学习指南竟然斩获超过 350k 的 star

    前段时间弄应届生学习指南的时候,整理了几个不错的开源文档,分享给小伙伴们!我觉得应该可以对大家有帮助. 本期文章对应的视频地址:https://www.bilibili.com/video/BV1xZ ...

  7. 2.8 CE修改器:寻找共享代码

    本关我们将学习共享代码,在C语言中角色属性都是以结构体的方式进行存储的,而结构体所存储的信息都是连续性的,这一关我们将会解释如何处理游戏中的共用代码,这种代码是通用在除了自己以外的其他同类型对像上的常 ...

  8. 佳翼M2X16 PCIE4.0X16转4盘M.2NVME固态硬盘 - 我的硬件配置

  9. 关于一些OJ上的\r以及\n以及字符串行输入的一些警示

    \r,\n,\r\n的区别 - 小 天 - 博客园 (cnblogs.com) 这篇文章详细的解释了在Windows系统和Linux系统下的换行的区别 概括的说,就是Windows系统下的" ...

  10. 全脸 苦思设计了半年的注册中心,与spring cloud 的做法 基本一致

    早知道不去自己思考设计了,害死了不少脑细胞,物理层的东西,所有设计者的思路 都基本一致: 没有必要每个微服务都要做一次安全校验,一个物理集群,一个网关: 网关校验token后,把用户信息 保存到 ht ...