天天看點

如何優雅地編寫緩存代碼

作者:閃念基因

在日常的編碼實踐中,經常會用到緩存來解決高并發問題,緩存可以說是解決流量洪峰的不二利器。雖然集團中間件團隊已經建構了緩存的基礎設施,已經幫助我們解決了絕大部分問題,但是在實際的編碼使用過程中,應用端調用緩存API時還是存在下述幾類問題:

  1. 使用緩存的邏輯非常通用,基本都是先查緩存,有直接傳回,沒有查DB,再放入緩存中。這段通用邏輯散落在系統的各個地方,違反了高内聚低耦合的原則。
  2. 緩存代碼和業務邏輯代碼深度耦合在一起,不僅降低了代碼的可讀性,還額外增加了系統複雜度。
  3. 如果要切換緩存(MDB->LDB)或者API更新時,所有涉及代碼都需要改動。
  4. 如果要解決緩存擊穿、緩存穿透、級聯緩存等類似通用問題時,都需要通過架構去解決。

是以,緩存是什麼,如何選擇某一種緩存,都不是本文重點,今天就寫寫實際編碼過程中,如何将緩存代碼從業務代碼中剝離出來,促使代碼更簡潔,更便于閱讀。

如何優雅地編寫緩存代碼

實踐分析

先讀取緩存資料,如果有資料則直接傳回,如果沒有讀取到資料,則讀取DB資料,等資料傳回後,再更新緩存。

如何優雅地編寫緩存代碼

這種場景,在日常編碼中,很常見,太簡單,但是實際的代碼确實很不一樣,列舉如下幾種:

▐傳統寫法

使用什麼緩存,就直接使用,嵌入到業務代碼中。這種代碼不管是code review,還是後人學習業務代碼時,都不想看,道理很簡單,跟實際的業務功能無關,我不想知道你用什麼緩存,你是怎麼編碼緩存代碼的。

如何優雅地編寫緩存代碼
如何優雅地編寫緩存代碼

▐進階一點的寫法

相比傳統的寫法,為了解決緩存各種資料格式(List、Map等),各種對象序列化問題(java、json),團隊内可以針對緩存這塊,封裝成簡單的API,友善大家使用。使用簡單了,但代碼依然嵌入在業務代碼中,沒有剝離出來。

如何優雅地編寫緩存代碼
如何優雅地編寫緩存代碼

▐注解寫法

最後是注解寫法,相對前兩種寫法,代碼已從業務代碼中剝離出來,閱讀代碼的人,隻會關心業務功能是如何實作的,使用哪個緩存,如何實作的,完全可以忽略。

如何優雅地編寫緩存代碼
如何優雅地編寫緩存代碼

spring cache方案分析

spring cache利用動态代理的方式,在代理類中處理緩存的相關操作,同時調用被代理類中的方法,進而可以使操作緩存的代碼和業務代碼分離,并且後期需要強化緩存能力時,也隻需要修改代理類中的方法即可。

如何優雅地編寫緩存代碼

以上就是Spring Cache的原理。Spring Cache是Spring提供的通用緩存架構。它利用了AOP,實作了基于注解的緩存功能,使開發者不用關心底層使用了什麼緩存架構,隻需要在方法上簡單地加一個注解,就能實作緩存功能了。使用者使用Spring Cache,可以快速開發一個很不錯的緩存功能。

▐代碼目錄

如何優雅地編寫緩存代碼

▐注解導圖

如何優雅地編寫緩存代碼

▐注解使用示例

@Cacheable(value = "user_cache", unless = "#result == null")
public User getUserById(Long id) {
 return userMapper.getUserById(id);
}
@CachePut(value = "user_cache", key = "#user.id", unless = "#result == null")
public User updateUser(User user) {
 userMapper.updateUser(user);
 return user;
}
@CacheEvict(value = "user_cache", key = "#id")
public void deleteUserById(Long id) {
 userMapper.deleteUserById(id);
}           

▐方案分析

Spring Cache的功能很強大,設計也非常優雅。特别适合緩存控制沒有那麼細緻的場景,比如偏靜态展示頁面,點贊數、排名等等,這些場景的特點是對資料實時性沒有那麼嚴格的要求,隻需要将資料源緩存下來,過期之後自動重新整理即可。這些場景下,Spring Cache就是神器,能大幅度提升研發效率。

但在高并發大資料量的場景下,精細的緩存顆粒度的控制上,還是需要做功能擴充。

  1. 多級緩存;
  2. 緩存定期重新整理;
  3. 清單緩存;
  4. 緩存cpp保護機制;
  5. 緩存計數。

例如:Spring Cache并沒有二級緩存的實作

如何優雅地編寫緩存代碼
如何優雅地編寫緩存代碼

自定義cache方案

學習spring cache架構方案,實作自定義cache架構,不僅保留spring cache架構的優點,同時實作spring cache很多缺失的能力,例如緩存擊穿、緩存穿透保護,多級緩存等。

▐注解代碼示例

如何優雅地編寫緩存代碼
如何優雅地編寫緩存代碼

▐方案架構

如何優雅地編寫緩存代碼
如何優雅地編寫緩存代碼

寫在最後面

借助spring cache實作方式,建構自定義緩存架構,擴充了很多注解,例如計數、緩存重新整理、清單緩存、分布式鎖、多級緩存等,不僅實作了緩存代碼和業務代碼的分離,同時拓展了spring緩存的能力,極大的提升了代碼的可讀性,降低了緩存代碼維護的效率。

作者:巧凡

來源-微信公衆号:大淘寶技術

出處:https://mp.weixin.qq.com/s/ZHMKPBtMfTD8vCAPdc99YQ