干掉RedisHelper,請這樣用分布式緩存

前言

我們在項目中使用Redis時通常是寫一個單例模式的RedisHelper靜態類,暴露一些常用的GetSet等操作,在需要使用地方直接RedisHelper.StringGet(xx,xx)就可以了,這樣雖然簡單粗暴地滿足我們對Redis的所有操作需要,但是這在Asp.Net Core的項目顯得不是那么優雅了。首先你的RedisHelper靜態類無法使用Asp.Net Core容器,又如何優雅的通過依賴注入獲取IConfiguration中的配置項呢?既然我們使用Asp.Net Core這么優秀的框架,最佳實踐當然就是遵循官方建議的開發規范優雅的編寫代碼。

IDistributedCache

若要使用 SQL Server 分布式緩存,請添加對 Microsoft.Extensions.Caching.SqlServer 包的包引用。

若要使用 Redis 分布式緩存,請添加對 Microsoft.Extensions.Caching.StackExchangeRedis 包的包引用。

若要使用 NCache 分布式緩存,請添加對 NCache.Microsoft.Extensions.Caching.OpenSource 包的包引用。

無論選擇哪種實現,應用都將使用 IDistributedCache 接口與緩存進行交互。

來看下IDistributedCache這個接口的定義

namespace?Microsoft.Extensions.Caching.Distributed;///?<summary>
///?Represents?a?distributed?cache?of?serialized?values.
///?</summary>
public?interface?IDistributedCache
{///?<summary>///?Gets?a?value?with?the?given?key.///?</summary>byte[]??Get(string?key);///?<summary>///?Gets?a?value?with?the?given?key.///?</summary>Task<byte[]?>?GetAsync(string?key,?CancellationToken?token?=?default(CancellationToken));void?Set(string?key,?byte[]?value,?DistributedCacheEntryOptions?options);///?<summary>///?Sets?the?value?with?the?given?key.///?</summary>Task?SetAsync(string?key,?byte[]?value,?DistributedCacheEntryOptions?options,?CancellationToken?token?=?default(CancellationToken));///?<summary>///?Refreshes?a?value?in?the?cache?based?on?its?key,?resetting?its?sliding?expiration?timeout?(if?any).///?</summary>void?Refresh(string?key);///?<summary>///?Refreshes?a?value?in?the?cache?based?on?its?key,?resetting?its?sliding?expiration?timeout?(if?any).///?</summary>Task?RefreshAsync(string?key,?CancellationToken?token?=?default(CancellationToken));///?<summary>///?Removes?the?value?with?the?given?key.///?</summary>void?Remove(string?key);///?<summary>///?Removes?the?value?with?the?given?key.///?</summary>Task?RemoveAsync(string?key,?CancellationToken?token?=?default(CancellationToken));
}

IDistributedCache 接口提供以下方法來處理分布式緩存實現中的項:

  • GetGetAsync:如果在緩存中找到,則接受字符串鍵并以 byte[] 數組的形式檢索緩存項。

  • SetSetAsync:使用字符串鍵將項(作為 byte[] 數組)添加到緩存。

  • RefreshRefreshAsync:根據鍵刷新緩存中的項,重置其可調到期超時(如果有)。

  • RemoveRemoveAsync:根據字符串鍵刪除緩存項。

干掉RedisHelper

官方不僅提出了如何最佳實踐分布式緩存的使用,還提供了基本的實現庫給我們直接用,比如我們在項目中用Redis為我們提供緩存服務:

  1. 添加引用Microsoft.Extensions.Caching.StackExchangeRedis

  2. 注冊容器AddStackExchangeRedisCache,并配置參數

builder.Services.AddStackExchangeRedisCache(options?=>{options.Configuration?=?builder.Configuration.GetConnectionString("MyRedisConStr");options.InstanceName?=?"SampleInstance";});
  1. 在需要使用Redis的地方通過構造函數注入IDistributedCache實例調用即可

這樣就可以優雅的使用Redis了,更加符合Asp.Net Core的設計風格,養成通過容器注入的方式來調用我們的各種服務,而不是全局使用RedisHelper靜態類,通過IOC的方式,結合面向接口開發,能方便的替換我們的實現類,統一由容器提供對象的創建,這種控制反轉帶來的好處只可意會不可言傳,這里就不贅述了。

AddStackExchangeRedisCache到底干了什么

上面已經知道如何優雅的使用我們的Redis了,但是不看下源碼就不知道底層實現,總是心里不踏實的。

2d1bdfad374199e8c98804ca597edb72.png

源碼比較好理解的,因為這個Nuget包的源碼也就四個類,而上面注冊容器的邏輯也比較簡單
AddStackExchangeRedisCache主要干的活

//?1.啟用Options以使用IOptions
services.AddOptions();
//?2.注入配置自定義配置,可以通過IOptions<T>注入到需要使用該配置的地方
services.Configure(setupAction);
//?3.注入一個單例IDistributedCache的實現類RedisCache
services.Add(ServiceDescriptor.Singleton<IDistributedCache,?RedisCache>());

所以我們在需要用Redis的地方通過構造函數注入IDistributedCache,而它對應的實現就是RedisCache,那看下它的源碼。

80279ad788105f0e569bfeb58ae716b3.png這里就不細看所有的實現了,重點只需要知道它繼承了IDistributedCache就行了,通過AddStackExchangeRedisCache傳入的ConnectionString,實現IDistributedCacheGetSetRefreshRemove四個核心的方法,我相信這難不倒你,而它也就是干了這么多事情,只不過它的實現有點巧妙。17dfb5d6274ccef127b2e653c852e3fb.png通過LUA腳本和HSET數據結構實現,HashKey是我們傳入的InstanceName+key,做了一層包裝。

源碼中還有需要注意的就是,我們要保證Redis連接對象IConnectionMultiplexer的單例,不能重復創建多個實例,這個想必在RedisHelper中也是要保證的,而且是通過lock來實現的。

然而微軟不是那么用的,玩了個花樣,注意下面的_connectionLock.Wait();

private?readonly?SemaphoreSlim?_connectionLock?=?new?SemaphoreSlim(initialCount:?1,?maxCount:?1);[MemberNotNull(nameof(_cache),?nameof(_connection))]
private?void?Connect()
{CheckDisposed();if?(_cache?!=?null){Debug.Assert(_connection?!=?null);return;}_connectionLock.Wait();try{if?(_cache?==?null){if?(_options.ConnectionMultiplexerFactory?==?null){if?(_options.ConfigurationOptions?is?not?null){_connection?=?ConnectionMultiplexer.Connect(_options.ConfigurationOptions);}else{_connection?=?ConnectionMultiplexer.Connect(_options.Configuration);}}else{_connection?=?_options.ConnectionMultiplexerFactory().GetAwaiter().GetResult();}PrepareConnection();_cache?=?_connection.GetDatabase();}}finally{_connectionLock.Release();}Debug.Assert(_connection?!=?null);
}

通過SemaphoreSlim限制同一時間只能有一個線程能訪問_connectionLock.Wait();后面的代碼。

學到裝逼技巧+1

思考

IDistributedCache只有四個操作:GetSetRefreshRemove,我們表示很希望跟著官方走,但這個接口過于簡單,不能滿足我的其他需求咋辦?
比如我們需要調用 StackExchange.Redis封裝的LockTake,LockRelease來實現分布式鎖的功能,那該怎么通過注入IDistributedCache調用?我們可以理解官方上面是給我們做了示范,我們完全可以自己定義一個接口,比如:

public?interface?IDistributedCachePlus?:?IDistributedCache
{bool?LockRelease(string?key,?byte[]?value);bool?LockTake(string?key,?byte[]?value,?TimeSpan?expiry);
}

繼承IDistributedCache,對其接口進行增強,然后自己實現實現AddStackExchangeRedisCache的邏輯,我們不用官方給的實現,但是我們山寨官方的思路,實現任意標準的接口,滿足我們業務。

services.Add(ServiceDescriptor.Singleton<IDistributedCachePlus,?RedisCachePlus>());

在需要使用緩存的地方通過構造函數注入IDistributedCachePlus

總結

官方提供的IDistributedCache標準及其實現類庫,能方便的實現我們對緩存的簡單的需求,通過遵循官方的建議,我們干掉了RedisHelper,優雅的實現了分布式Redis緩存的使用,你覺得這樣做是不是很優雅呢?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/287252.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/287252.shtml
英文地址,請注明出處:http://en.pswp.cn/news/287252.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

4個常用的awk統計命令

1、求和cat data|awk {sum$1} END {print "Sum ", sum}2、求平均cat data|awk {sum$1} END {print "Average ", sum/NR}3、求最大值cat data|awk BEGIN {max 0} {if ($1>max) max$1 fi} END {print "Max", max}4、求最小值&#xff08;min…

《看聊天記錄都學不會C#?太菜了吧》(2)C#那么簡單我為何之前還學C語言?

本系列文章將會以通俗易懂的對話方式進行教學&#xff0c;對話中將涵蓋了新手在學習中的一般問題。此系列將會持續更新&#xff0c;包括別的語言以及實戰都將使用對話的方式進行教學&#xff0c;基礎編程語言教學適用于零基礎小白&#xff0c;之后實戰課程也將會逐步更新。 若…

Android之java.lang.ClassCastException: *****cannot be cast to*******

1 問題 在寫BaseMultiItemQuickAdapter適配器的時候&#xff0c;更具不同類型構建不同的實體對象&#xff0c;提示錯誤如下 2 原因 Overrideprotected void convert(BaseViewHolder helper, MultiItemEntity item) {switch (helper.getItemViewType()) {case AppCleanHead.app…

php函數的初步使用

通過調用函數&#xff0c;實現打印半金字塔、全金字塔、空心金字塔、菱形、空心菱形 調用例程 huaTuMain.php被調用函數 huaTu.php轉載于:https://www.cnblogs.com/seaBiscuit0922/p/5613141.html

ORACLE 11G DATA GUARD主從切換

當oracle data guard中如主庫出現當機時,需要將從庫切換為主庫,以下從實驗環境模擬主從庫切換操作:1.查看主從庫角色192.168.88.120:192.168.88.119:2.將主庫(88.120)切換為從庫alter database commit to switchover to physical standby with sessionB shutdown;shutdown im…

【Pix4d精品教程】大疆精靈4A無人機航空攝影測量外業數據采集完整操作流程

本項目我們采用大疆精靈4A無人機進行航空攝影測量外業數據采集,主要內容包括:航攝準備、像控點布設、航線規劃、飛行、數據傳輸等。 Pix4dmapper攝影測量內業數據處理、空三及4D產品生產部分,請參照文章:《Pix4dmapper攝影測量內業數據處理完整流程》 目錄 一、航攝準備 …

oracle進程結構中完成更新,Oracle 進程結構

Oracle進程結構進程是動態創建的&#xff0c;完成任務后就消亡&#xff1b;而程序是靜態的實體&#xff0c;程序是可以復制、編輯的。進程強調的是執行過程&#xff0c;而程序僅僅是指令的有序集合&#xff1b;進程在內存中&#xff0c;程序在外存中。ORACLE分為用戶進程和ORAC…

國外設計師眼中的原型工具Mockplus

2019獨角獸企業重金招聘Python工程師標準>>> 今天&#xff0c;我們評述一款新型設計工具&#xff0c;Mockplus&#xff0c;專為設計師而打造的創新性原型設計工具。Mockplus適合于各種應用軟件的制作&#xff0c;無論是手機應用&#xff0c;網頁應用&#xff0c;亦或…

《看聊天記錄都學不會C#?太菜了吧》(1)從今天開始我是一個游戲開發者

本系列文章將會以通俗易懂的對話方式進行教學&#xff0c;對話中將涵蓋了新手在學習中的一般問題。此系列將會持續更新&#xff0c;包括別的語言以及實戰都將使用對話的方式進行教學&#xff0c;基礎編程語言教學適用于零基礎小白&#xff0c;之后實戰課程也將會逐步更新。 若…

Android之讓EditText不被鍵盤擋住

1 問題 點擊EditText的時候&#xff0c;鍵盤擋住了&#xff0c;不好輸入內容 2 解決辦法 在AndroidManifest.xml相應的activity里面添加 android:windowSoftInputMode"adjustPan|stateHidden"

如何定制.NET6.0的日志記錄

在本章中&#xff0c;也就是整個系列的第一部分將介紹如何定制日志記錄(系列內容查閱《玩轉ASP.NET 6.0框架-序言》)。默認日志記錄僅寫入控制臺或調試窗口&#xff0c;這在大多數情況下都很好&#xff0c;但有時需要寫入到文件或數據庫&#xff0c;或者&#xff0c;您可能希望…

FreeMarker標簽介紹

轉自&#xff1a;http://www.blogjava.net/kxbin/articles/366505.html FreeMarker標簽使用 一、FreeMarker模板文件主要有4個部分組成 1、文本&#xff0c;直接輸出的部分 2、注釋&#xff0c;即<#--...-->格式不會輸出 3、插值&#xff08;Interpolation&#xff09…

利用Erdas監督分類方法提取城鎮用地信息完整實驗操作步驟

打開erdas,分波段加載landsat TM 影像信息,并轉成img圖像格式文件。 1.打開erdas,點擊viewer打開新窗口,點擊打開圖標,選擇要加載的一個波段的tif圖像,點擊OK。 2.點擊主窗口File——Save——Top Layer As…,在跳出的Save窗

linux命令 su和sudo,Linux中sudo和su的區別

介紹&#xff1a;主要對su和sudo的功能&#xff0c;區別以及使用進行介紹。兩者之間的區別su用于用戶之間的切換&#xff1b;sudo用于普通用戶可以使用root權限來執行指定命令&#xff1b;命令介紹1. susu簡介su用于用戶之間的切換。但是前面的用戶依然保持在登錄狀態。這種切換…

通過Xshell上傳下載文件

2019獨角獸企業重金招聘Python工程師標準>>> 1&#xff09;安裝模塊 yum install lrzsz 2&#xff09;使用命令 rz #上傳文件到Linux sz hello.txt #從Linux下載文件hello.txt 轉載于:https://my.oschina.net/u/2351685/blog/519941

Centos 安裝配置 vsftpd

為什么80%的碼農都做不了架構師&#xff1f;>>> 一、安裝vsftpd 執行 yum -y install vsftpd (rpm -qa|grep vsftpd 可查看是否已安裝vsftpd, 默認配置文件在/etc/vsftpd/vsftpd/conf) 二、創建虛擬用戶 選擇在根目錄或者用戶目錄下創建ftp文件夾&#xff1a;mkdir…

《看聊天記錄都學不會Python到游戲實戰?太菜了吧》(6)不會這個知識點代碼越寫越難

本系列文章將會以通俗易懂的對話方式進行教學&#xff0c;對話中將涵蓋了新手在學習中的一般問題。此系列將會持續更新&#xff0c;包括別的語言以及實戰都將使用對話的方式進行教學&#xff0c;基礎編程語言教學適用于零基礎小白&#xff0c;之后實戰課程也將會逐步更新。 若…

Android之各個手機版本WiFi熱點的創建

1 問題 Android手機創建熱點,有很多兼容性問題,網上有很多例子,但是不夠全,而且高版本反射很多奔潰,我這里再總結下。 2 版本兼容和需要的權限已經熱點IP地址說明 1)AndroidMainifest.xml里面需要添加的權限 <uses-permission android:name="android.permissio…

你還在用GIF?那就out了

前言今天介紹一篇使用json格式在wpf中播放動畫效果&#xff1b;正文話說在上古&#xff08;1987&#xff09;時代&#xff0c;Gif因其體積小成像相對清晰和非常強的兼容性&#xff0c;而大受歡迎;Gif也因為當時的技術限制導致很多缺陷 這包括對電腦的內存和性能占用非常大;同時…

【攝影測量原理】第一章:攝影測量學基礎

目 錄 第一節 攝影測量學的定義、任務 第二節 攝影測量與遙感的分類 第三節 攝影測量與遙感的發展歷程 第四節 遙感主要應用領域及3S技術 第一節 攝影測量學的定義、任務 先來看一下例子&#xff1a; 思考&#xff1a; 1、攝影測量去常規測量的相同點與不同點&#…