點選關註公眾號,Java幹貨 及時送達 👇
什麽是緩存預熱?
緩存預熱是一種在程式啟動或緩存失效之後,主動將熱點數據載入到緩存中的策略。這樣,在實際請求到達程式時,熱點數據已經存在於緩存中,從而減少了緩存穿透和緩存擊穿的情況,也緩解了SQL伺服器的壓力。
實作
緩存抽象類
首先我們先來實作一個緩存抽象類,這個抽象類的作用就是在將來我們需要將某個模組的數據需要提前載入到緩存中的時候,我們可以建立一個它的實作類,來進行數據的緩存與載入,具體使用方式請看後邊我寫的例子。
public abstract class AbstractCache {
/**
* 緩存
*/
protected abstract void init();
/**
* 獲取緩存
*
* @param <T>
* @return
*/
public abstract <T> T get();
/**
* 清理緩存
*/
public abstract void clear();
/**
* 重新載入
*/
public void reload() {
clear();
init();
}
}
Spring上下文工具類
接下來我們實作一個Spring的上下文工具類,這個工具類需要實作ApplicationContextAware
,作用就是負責管理bean的載入與例項化的,具體如何使用,請往下繼續閱讀。
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextUtil.applicationContext = applicationContext;
}
/**
* 獲取上下文
* @return
*/
public static ApplicationContext getContext() {
return applicationContext;
}
}
緩存預熱
然後我們來實作,在程式啟動後,直接進行數據的緩存載入,這個類需要實作CommandLineRunner
介面,這個介面提供的方法作用就是在程式啟動後自動執行。
這個實作類裏,我們使用ApplicationContextUtil
工具類來獲取上下文,然後透過getBeansOfType
方法獲取實作AbstractCache
抽象類的子類別,返回的是一個Map型別的集合,接下來透過getBean方法以多型的方式例項化子類別,最後我們呼叫抽象類的init方法即可。
如果有多個實作類,使用@Order註解標註先後執行就可以了。
@Component
@ConditionalOnProperty(name = {"cache.init.enable"}, havingValue = "true", matchIfMissing = false)
public class CachePreheatHandler implements CommandLineRunner {
/**
* 緩存預熱
* @param args
* @throws Exception
*/
@Override
public void run(String... args) throws Exception {
ApplicationContext context = ApplicationContextUtil.getContext();
Map<String, AbstractCache> beansOfType = context.getBeansOfType(AbstractCache. class);
for (Map.Entry<String, AbstractCache> cacheEntry : beansOfType.entrySet()) {
AbstractCache cache = context.getBean(cacheEntry.getValue().get class());
cache.init();
}
}
}
解釋:
@ConditionalOnProperty
這個註解在這裏的作用是,需要在配置檔開啟cache.init.enable
,理想值是true,預設值是false。
cache.init.enable=true
使用
我們就以新聞熱點為例,資料庫中有一張tb_news新聞表,均為微博熱搜體育榜內容。
接下來建立一個AbstractCache
的實作類,來實作具體的實作
@Component
@RequiredArgsConstructor
public class NewsCache extends AbstractCache {
private static final String NEWS_KEY = "news";
private final RedisTemplate<String, Object> redisTemplate;
private final NewsService newsService;
@Override
protected void init() {
if (Boolean.FALSE.equals(redisTemplate.hasKey(NEWS_KEY))) {
redisTemplate.opsForValue().set(NEWS_KEY, newsService.list(), 30, TimeUnit.MINUTES);
}
}
@Override
public <T> T get() {
if (Boolean.FALSE.equals(redisTemplate.hasKey(NEWS_KEY))) {
reload();
}
return (T) redisTemplate.opsForValue().get(NEWS_KEY);
}
@Override
public void clear() {
redisTemplate.delete(NEWS_KEY);
}
}
然後啟動計畫,我們就發現,Redis中已經存好了熱點數據
最後可以透過get方法獲取數據了,也不用擔心數據過期了。
@RestController
@RequestMapping("/news")
@RequiredArgsConstructor
public class NewsController {
private final NewsCache newsCache;
@GetMapping("/cache")
public List<News> list() {
return newsCache.get();
}
}
好了,小夥伴們,今天的分享就到此結束了,歡迎留出建議,如果覺得內容可以,還請來個點贊和關註吧!
來源|juejin.cn/post/7287907117336526863
END
看完本文有收獲?請轉發分享給更多人
關註「Java編程鴨」,提升Java技能
關註Java編程鴨微信公眾號,後台回復:碼農大禮包可以獲取最新整理的技術資料一份。涵蓋Java 框架學習、架構師學習等!
文章有幫助的話,在看,轉發吧。
謝謝支持喲 (*^__^*)