javascript
SpringBoot 使用 Caffeine 本地缓存
文章目錄
- 一、本地緩存介紹
- 二、緩存組件 Caffeine 介紹
- 2.1. Caffeine 性能
- 2.2. Caffeine 配置說明
- 2.3. 軟引用與弱引用
- 三、SpringBoot 集成 Caffeine 方式一
- 3.1. Maven 引入相關依賴
- 3.2. 配置緩存配置類
- 3.3. 定義實體對象
- 3.4. 定義服務接口類
- 3.5. 定義服務接口實現類
- 3.6. Caffeine工具類
- 3.7. 測試案例
- 四、測試案例
- 4.1. 添加用戶
- 4.2. 查詢用戶
- 4.3. 更新用戶
- 4.4. 刪除用戶
- 4.5. 效果圖
- 五、第二種整合方式
- 5.1. 依賴
- 5.2. 接口實現類(替換)
一、本地緩存介紹
緩存在日常開發中啟動至關重要的作用,由于是存儲在內存中,數據的讀取速度是非常快的,能大量減少對數據庫的訪問,減少數據庫的壓力。
之前介紹過 Redis 這種 NoSql 作為緩存組件,它能夠很好的作為分布式緩存組件提供多個服務間的緩存,但是 Redis 這種還是需要網絡開銷,增加時耗。本地緩存是直接從本地內存中讀取,沒有網絡開銷,例如秒殺系統或者數據量小的緩存等,比遠程緩存更合適。
二、緩存組件 Caffeine 介紹
按 Caffeine Github 文檔描述,Caffeine 是基于 JAVA 8 的高性能緩存庫。并且在 spring5 (springboot 2.x) 后,spring 官方放棄了 Guava,而使用了性能更優秀的 Caffeine 作為默認緩存組件。
2.1. Caffeine 性能
可以通過下圖觀測到,在下面緩存組件中 Caffeine 性能是其中最好的。
2.2. Caffeine 配置說明
注意:
weakValues 和 softValues 不可以同時使用。
maximumSize 和 maximumWeight 不可以同時使用。
expireAfterWrite 和 expireAfterAccess 同事存在時,以 expireAfterWrite 為準。
2.3. 軟引用與弱引用
軟引用:如果一個對象只具有軟引用,則內存空間足夠,垃圾回收器就不會回收它;如果內存空間不足了,就會回收這些對象的內存。
弱引用:弱引用的對象擁有更短暫的生命周期。在垃圾回收器線程掃描它所管轄的內存區域的過程中,一旦發現了只具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存.
// 軟引用 Caffeine.newBuilder().softValues().build();// 弱引用 Caffeine.newBuilder().weakKeys().weakValues().build();三、SpringBoot 集成 Caffeine 方式一
3.1. Maven 引入相關依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--字符串工具類--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.12.0</version></dependency><dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>3.2. 配置緩存配置類
package com.gblfy.config;import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;import java.util.concurrent.TimeUnit;/*** 本地caffeine緩存配置** @author gblfy* @date 2022-03-15*/ @Configuration public class CaffeineCacheConfig {@Beanpublic Cache<String, Object> caffeineCache() {return Caffeine.newBuilder()// 設置最后一次寫入或訪問后經過固定時間過期.expireAfterWrite(6000, TimeUnit.SECONDS)// 初始的緩存空間大小.initialCapacity(100)// 緩存的最大條數.maximumSize(1000).build();} }3.3. 定義實體對象
package com.gblfy;import lombok.Data; import lombok.ToString;@Data @ToString public class UserInfo {private Integer id;private String name;private String sex;private Integer age; }3.4. 定義服務接口類
package com.gblfy.service;import com.gblfy.entity.UserInfo;/*** 用戶模塊接口** @author gblfy* @date 2022-03-15*/ public interface UserInfoService {/*** 增加用戶信息** @param userInfo 用戶信息*/void addUserInfo(UserInfo userInfo);/*** 獲取用戶信息** @param id 用戶ID* @return 用戶信息*/UserInfo getByName(Integer id);/*** 修改用戶信息** @param userInfo 用戶信息* @return 用戶信息*/UserInfo updateUserInfo(UserInfo userInfo);/*** 刪除用戶信息** @param id 用戶ID*/void deleteById(Integer id);}3.5. 定義服務接口實現類
package com.gblfy.service.impl;import com.gblfy.entity.UserInfo; import com.gblfy.service.UserInfoService; import com.gblfy.uitls.CaffeineUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;import java.util.Map; import java.util.concurrent.ConcurrentHashMap;/*** 用戶模塊接口實現類** @author gblfy* @date 2022-03-15*/ @Slf4j @Service public class UserInfoServiceImpl implements UserInfoService {/*** 模擬數據庫存儲數據*/private Map<Integer, UserInfo> userInfoMap = new ConcurrentHashMap<>();@Autowiredprivate CaffeineUtils caffeineUtils;@Overridepublic void addUserInfo(UserInfo userInfo) {log.info("create");userInfoMap.put(userInfo.getId(), userInfo);// 加入緩存caffeineUtils.putAndUpdateCache(String.valueOf(userInfo.getId()), userInfo);}@Overridepublic UserInfo getByName(Integer userId) {// 先從緩存讀取UserInfo userInfo = caffeineUtils.getObjCacheByKey(String.valueOf(userId), UserInfo.class);if (userInfo != null) {return userInfo;}// 如果緩存中不存在,則從庫中查找log.info("get");userInfo = userInfoMap.get(userId);// 如果用戶信息不為空,則加入緩存if (userInfo != null) {caffeineUtils.putAndUpdateCache(String.valueOf(userInfo.getId()), userInfo);}return userInfo;}@Overridepublic UserInfo updateUserInfo(UserInfo userInfo) {log.info("update");if (!userInfoMap.containsKey(userInfo.getId())) {return null;}// 取舊的值UserInfo oldUserInfo = userInfoMap.get(userInfo.getId());// 替換內容if (StringUtils.isNotBlank(oldUserInfo.getName())) {oldUserInfo.setName(userInfo.getName());}if (StringUtils.isNotBlank(oldUserInfo.getSex())) {oldUserInfo.setSex(userInfo.getSex());}oldUserInfo.setAge(userInfo.getAge());// 將新的對象存儲,更新舊對象信息userInfoMap.put(oldUserInfo.getId(), oldUserInfo);// 替換緩存中的值caffeineUtils.putAndUpdateCache(String.valueOf(oldUserInfo.getId()), oldUserInfo);return oldUserInfo;}@Overridepublic void deleteById(Integer id) {log.info("delete");userInfoMap.remove(id);// 從緩存中刪除caffeineUtils.removeCacheByKey(String.valueOf(id));}}3.6. Caffeine工具類
package com.gblfy.uitls;import com.github.benmanes.caffeine.cache.Cache; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;/*** Caffeine緩存工具類** @Author gblfy* @Date 2022-03-15 14:58**/ @Component public class CaffeineUtils {@AutowiredCache<String, Object> caffeineCache;/*** 添加或更新緩存** @param key* @param value*/public void putAndUpdateCache(String key, Object value) {caffeineCache.put(key, value);}/*** 獲取對象緩存** @param key* @return*/public <T> T getObjCacheByKey(String key, Class<T> t) {caffeineCache.getIfPresent(key);return (T) caffeineCache.asMap().get(key);}/*** 根據key刪除緩存** @param key*/public void removeCacheByKey(String key) {// 從緩存中刪除caffeineCache.asMap().remove(key);} }3.7. 測試案例
package com.gblfy;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*;/*** 用戶模塊入口** @author gblfy* @date 2022-03-15*/ @RestController @RequestMapping public class UserInfoController {@Autowiredprivate UserInfoService userInfoService;@GetMapping("/userInfo/{id}")public Object getUserInfo(@PathVariable Integer id) {UserInfo userInfo = userInfoService.getByName(id);if (userInfo == null) {return "沒有該用戶";}return userInfo;}@PostMapping("/userInfo")public Object createUserInfo(@RequestBody UserInfo userInfo) {userInfoService.addUserInfo(userInfo);return "SUCCESS";}@PutMapping("/userInfo")public Object updateUserInfo(@RequestBody UserInfo userInfo) {UserInfo newUserInfo = userInfoService.updateUserInfo(userInfo);if (newUserInfo == null) {return "不存在該用戶";}return newUserInfo;}@DeleteMapping("/userInfo/{id}")public Object deleteUserInfo(@PathVariable Integer id) {userInfoService.deleteById(id);return "SUCCESS";}}四、測試案例
4.1. 添加用戶
請求方式:POST content-type:application/json 測試地址:localhost:8080/userInfo報文內容
{'id':1,'name':"yx",'sex':"女",'age':2 }4.2. 查詢用戶
請求方式:GET 測試地址:localhost:8080/userInfo/14.3. 更新用戶
請求方式:PUT content-type:application/json 測試地址:localhost:8080/userInfo報文內容
{'id':1,'name':"gblfy",'sex':"男",'age':22 }4.4. 刪除用戶
請求方式:DELETE 測試地址:localhost:8080/userInfo/14.5. 效果圖
五、第二種整合方式
5.1. 依賴
上面基礎上添加
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency>5.2. 接口實現類(替換)
package com.gblfy;import lombok.extern.slf4j.Slf4j; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils;import java.util.HashMap;/*** 用戶模塊接口實現類** @author gblfy* @date 2022-03-15*/ @Slf4j @Service @CacheConfig(cacheNames = "caffeineCacheManager") public class UserInfoServiceImpl implements UserInfoService {/*** 模擬數據庫存儲數據*/private HashMap<Integer, UserInfo> userInfoMap = new HashMap<>();@Override@CachePut(key = "#userInfo.id")public void addUserInfo(UserInfo userInfo) {log.info("create");userInfoMap.put(userInfo.getId(), userInfo);}@Override@Cacheable(key = "#id")public UserInfo getByName(Integer id) {log.info("get");return userInfoMap.get(id);}@Override@CachePut(key = "#userInfo.id")public UserInfo updateUserInfo(UserInfo userInfo) {log.info("update");if (!userInfoMap.containsKey(userInfo.getId())) {return null;}// 取舊的值UserInfo oldUserInfo = userInfoMap.get(userInfo.getId());// 替換內容if (!StringUtils.isEmpty(oldUserInfo.getAge())) {oldUserInfo.setAge(userInfo.getAge());}if (!StringUtils.isEmpty(oldUserInfo.getName())) {oldUserInfo.setName(userInfo.getName());}if (!StringUtils.isEmpty(oldUserInfo.getSex())) {oldUserInfo.setSex(userInfo.getSex());}// 將新的對象存儲,更新舊對象信息userInfoMap.put(oldUserInfo.getId(), oldUserInfo);// 返回新對象信息return oldUserInfo;}@Override@CacheEvict(key = "#id")public void deleteById(Integer id) {log.info("delete");userInfoMap.remove(id);}}總結
以上是生活随笔為你收集整理的SpringBoot 使用 Caffeine 本地缓存的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Centos/Red Hat6.8 安装
- 下一篇: vue 集成 Loading 加载效果