聊聊 Spring Data Redis本質(zhì)
今天花半小時(shí)補(bǔ)一篇技術(shù)文章純純是因?yàn)樵缟习l(fā)的那篇感悟隨記很多人可能會(huì)認(rèn)為不是技術(shù)文章。而一般這種文章的閱讀量會(huì)遠(yuǎn)高于技術(shù)文章。為了不破壞公眾號(hào)的基調(diào),今天寫篇技術(shù)文章明天一早發(fā)出去。大家上班路上看到的是:這還是一個(gè)技術(shù)公眾號(hào)。但是我想說的是上篇文章我是在講技術(shù),如果對(duì)技術(shù)的理解過于狹隘,那在工作中會(huì)很容易進(jìn)入瓶頸期。
咱們宏觀到微觀來審視一下:業(yè)務(wù)的服務(wù)在技術(shù)上需要解決4個(gè)問題:分布式、通信、存儲(chǔ)和服務(wù)治理。
圖片
在存儲(chǔ)方面,spring家族在使用時(shí)做了封裝就是spring data。spring data本質(zhì)上是解決與存儲(chǔ)層的通信問題,提供的是與存儲(chǔ)層的通信規(guī)范。Redis是其中一種常用的存儲(chǔ)。
在19年之前,Jedis還是主流的redis客戶端驅(qū)動(dòng),但是近幾年lettuce占據(jù)了主流的市場(chǎng)。這也是spring data redis的默認(rèn)支持。原因是當(dāng)一個(gè)Jedis連接要進(jìn)行多個(gè)不同的客戶端數(shù)據(jù)操作的時(shí)候有可能產(chǎn)生線程安全的問題,而且lettuce還支持響應(yīng)式編程的模式。就是說spring data redis本身支持同步和異步兩種編程模式,而lettuce支持同步、異步和響應(yīng)式三種編程模式。
首先來看lettuce是什么。它是一個(gè)驅(qū)動(dòng)。“驅(qū)動(dòng)”通常指的是一種軟件組件,它允許操作系統(tǒng)或應(yīng)用程序與硬件或其他軟件進(jìn)行交互。在 Java 和其他編程語言中,驅(qū)動(dòng)通常是指用于連接和操作特定類型數(shù)據(jù)庫、消息隊(duì)列或緩存等系統(tǒng)的庫或框架。
驅(qū)動(dòng)的四個(gè)作用
- 連接管理: 驅(qū)動(dòng)負(fù)責(zé)建立與 Redis 服務(wù)器的連接,并管理連接的生命周期。
- 命令執(zhí)行: 驅(qū)動(dòng)提供了方法來執(zhí)行 Redis 命令并處理返回的結(jié)果。
- 錯(cuò)誤處理: 驅(qū)動(dòng)處理與 Redis 交互時(shí)可能出現(xiàn)的錯(cuò)誤和異常。
- 數(shù)據(jù)類型支持: 驅(qū)動(dòng)通常會(huì)封裝 Redis 的數(shù)據(jù)類型(如字符串、哈希、列表等),提供更易用的接口。
所以不管是Jedis還是Lettuce,都會(huì)負(fù)責(zé)連接工廠的創(chuàng)建。
@Bean
public LettuceConnectionFactory connectionFactory() {
RedisStandaloneConfiguration cfg = new RedisStandaloneConfiguration();
cfg.setHostName(host);
cfg.setPort(Integer.parseInt(port));
cfg.setDatabase(database);
cfg.setPassword(password);
return new LettuceConnectionFactory(cfg);
}
實(shí)際使用的時(shí)候咱們還是使用RedisTemplate
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory factory) {
// 創(chuàng)建實(shí)例對(duì)象
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
template.afterPropertiesSet();
return template;
}
有沒有朋友有這樣的疑惑:RedisTemplate看這個(gè)名字應(yīng)該是使用了模板方法的設(shè)計(jì)模式,模板方法特征不是應(yīng)該提供一個(gè)抽象類,有不同的實(shí)現(xiàn)嗎?怎么看源碼好像也沒用啊。這個(gè)問題問得很好,年輕人。
為什么我知道你是個(gè)年輕人呢。因?yàn)镽edisTemplate在早期的版本中的確是一個(gè)抽象方法,具體使用的時(shí)候還是需要使用它的子類,那時(shí)候是一種基于行為模式的模板方法。而現(xiàn)在呢?
仍然是一個(gè)模板方法的設(shè)計(jì)模式,除了可以直接使用的RedisTemplate,我們其實(shí)還有StringRedisTemplate這個(gè)子類。后來又有了一個(gè)ReactiveRedisTemplate,它其實(shí)并不是RedisTemplate的子類。
咱們提到Lettuce是支持響應(yīng)式編程的。
響應(yīng)式編程是一種編程范式,強(qiáng)調(diào)異步數(shù)據(jù)流的處理和對(duì)變化的響應(yīng)。它允許程序以聲明性方式處理數(shù)據(jù)流和變化,通常用于處理用戶界面、事件驅(qū)動(dòng)的系統(tǒng)、流式數(shù)據(jù)等場(chǎng)景。響應(yīng)式編程的核心思想是將數(shù)據(jù)視為流,并對(duì)這些流中的變化作出反應(yīng)。
它有幾個(gè)核心概念:
- 數(shù)據(jù)流:
- 數(shù)據(jù)流是指一系列的數(shù)據(jù)變化或事件。響應(yīng)式編程中,數(shù)據(jù)流可以是用戶輸入、網(wǎng)絡(luò)請(qǐng)求、傳感器數(shù)據(jù)等。
- 觀察者模式:
響應(yīng)式編程通?;谟^察者模式,即一個(gè)對(duì)象(被觀察者)維護(hù)一系列依賴于它的對(duì)象(觀察者),并在其狀態(tài)發(fā)生變化時(shí)自動(dòng)通知這些觀察者。
異步處理:
響應(yīng)式編程強(qiáng)調(diào)非阻塞的異步處理,通過回調(diào)函數(shù)、Promises 或者流的方式來處理數(shù)據(jù)變化,而不是等待操作完成。
聲明性編程:
響應(yīng)式編程允許開發(fā)者以聲明的方式定義數(shù)據(jù)流的處理邏輯,而不是以命令式的方式逐步執(zhí)行。
響應(yīng)式編程的優(yōu)點(diǎn)
- 簡化異步編程: 通過將異步操作以流的形式處理,減少了回調(diào)地獄(callback hell)的問題。
- 提高可讀性: 代碼更簡潔,邏輯清晰,更容易理解和維護(hù)。
- 易于組合: 可以方便地將多個(gè)數(shù)據(jù)流進(jìn)行組合和轉(zhuǎn)換,形成復(fù)雜的邏輯。
回調(diào)地獄(Callback Hell)是指在使用異步編程時(shí),由于多層嵌套的回調(diào)函數(shù)導(dǎo)致代碼變得難以閱讀、理解和維護(hù)的現(xiàn)象。它通常發(fā)生在處理多個(gè)異步操作時(shí),每個(gè)操作都依賴于前一個(gè)操作的結(jié)果,導(dǎo)致代碼結(jié)構(gòu)像金字塔一樣逐漸加深。
回調(diào)地獄的特征
- 深層嵌套: 每個(gè)異步操作的結(jié)果都需要嵌套在另一個(gè)回調(diào)中,使得代碼層級(jí)過深。
- 可讀性差: 多層嵌套使得代碼難以理解,邏輯不清晰,增加了維護(hù)的難度。
- 錯(cuò)誤處理復(fù)雜: 在嵌套的回調(diào)中,錯(cuò)誤處理變得更加復(fù)雜,因?yàn)槊總€(gè)回調(diào)都需要單獨(dú)處理錯(cuò)誤。
Spring Data Redis默認(rèn)是異步的,而使用響應(yīng)式編程的公司實(shí)際也不多見。因?yàn)轫憫?yīng)式編程是受到環(huán)境制約的。它要基于WebFlex,而WebFlex與咱們常用的Web是二選一的。