做者:超級小豆丁
來源:http://www.mydlq.club/article/56/html
環境配置:java
緩存在平常開發中啓動相當重要的做用,因爲是存儲在內存中,數據的讀取速度是很是快的,能大量減小對數據庫的訪問,減小數據庫的壓力。git
以前介紹過 Redis 這種 NoSql 做爲緩存組件,它可以很好的做爲分佈式緩存組件提供多個服務間的緩存,可是 Redis 這種仍是須要網絡開銷,增長時耗。本地緩存是直接從本地內存中讀取,沒有網絡開銷,例如秒殺系統或者數據量小的緩存等,比遠程緩存更合適。github
按 Caffeine Github 文檔描述,Caffeine 是基於 JAVA 8 的高性能緩存庫。而且在 spring5 (springboot 2.x) 後,spring 官方放棄了 Guava,而使用了性能更優秀的 Caffeine 做爲默認緩存組件。web
能夠經過下圖觀測到,在下面緩存組件中 Caffeine 性能是其中最好的。spring
參數 | 類型 | 描述 |
---|---|---|
initialCapacity | integer | 初始的緩存空間大小 |
maximumSize | long | 緩存的最大條數 |
maximumWeight | long | 緩存的最大權重 |
expireAfterAccess | duration | 最後一次寫入或訪問後通過固定時間過時 |
refreshAfterWrite | duration | 最後一次寫入後通過固定時間過時 |
refreshAfterWrite | duration | 建立緩存或者最近一次更新緩存後通過固定的時間間隔,刷新緩存 |
weakKeys | boolean | 打開 key 的弱引用 |
weakValues | boolean | 打開 value 的弱引用 |
softValues | boolean | 打開 value 的軟引用 |
recordStats | - | 開發統計功能 |
注意:數據庫
weakValues
和 softValues
不能夠同時使用。maximumSize
和 maximumWeight
不能夠同時使用。expireAfterWrite
和 expireAfterAccess
同事存在時,以 expireAfterWrite
爲準。// 軟引用 Caffeine.newBuilder().softValues().build(); // 弱引用 Caffeine.newBuilder().weakKeys().weakValues().build();
SpringBoot 有倆種使用 Caffeine 做爲緩存的方式:apache
方式一: 直接引入 Caffeine 依賴,而後使用 Caffeine 方法實現緩存。緩存
方式二: 引入 Caffeine 和 Spring Cache 依賴,使用 SpringCache 註解方法實現緩存。springboot
下面將介紹下,這倆中集成方式都是如何實現的。
Spring Boot 基礎就不介紹了,推薦看下這個教程:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.2.RELEASE</version> </parent> <groupId>mydlq.club</groupId> <artifactId>springboot-caffeine-cache-example-1</artifactId> <version>0.0.1</version> <name>springboot-caffeine-cache-example-1</name> <description>Demo project for Spring Boot Cache</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
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; @Configuration public class CacheConfig { @Bean public Cache<String, Object> caffeineCache() { return Caffeine.newBuilder() // 設置最後一次寫入或訪問後通過固定時間過時 .expireAfterWrite(60, TimeUnit.SECONDS) // 初始的緩存空間大小 .initialCapacity(100) // 緩存的最大條數 .maximumSize(1000) .build(); } }
import lombok.Data; import lombok.ToString; @Data @ToString public class UserInfo { private Integer id; private String name; private String sex; private Integer age; }
UserInfoService
import mydlq.club.example.entity.UserInfo; 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); }
UserInfoServiceImpl
import com.github.benmanes.caffeine.cache.Cache; import lombok.extern.slf4j.Slf4j; import mydlq.club.example.entity.UserInfo; import mydlq.club.example.service.UserInfoService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import java.util.HashMap; @Slf4j @Service public class UserInfoServiceImpl implements UserInfoService { /** * 模擬數據庫存儲數據 */ private HashMap<Integer, UserInfo> userInfoMap = new HashMap<>(); @Autowired Cache<String, Object> caffeineCache; @Override public void addUserInfo(UserInfo userInfo) { log.info("create"); userInfoMap.put(userInfo.getId(), userInfo); // 加入緩存 caffeineCache.put(String.valueOf(userInfo.getId()),userInfo); } @Override public UserInfo getByName(Integer id) { // 先從緩存讀取 caffeineCache.getIfPresent(id); UserInfo userInfo = (UserInfo) caffeineCache.asMap().get(String.valueOf(id)); if (userInfo != null){ return userInfo; } // 若是緩存中不存在,則從庫中查找 log.info("get"); userInfo = userInfoMap.get(id); // 若是用戶信息不爲空,則加入緩存 if (userInfo != null){ caffeineCache.put(String.valueOf(userInfo.getId()),userInfo); } return userInfo; } @Override 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); // 替換緩存中的值 caffeineCache.put(String.valueOf(oldUserInfo.getId()),oldUserInfo); return oldUserInfo; } @Override public void deleteById(Integer id) { log.info("delete"); userInfoMap.remove(id); // 從緩存中刪除 caffeineCache.asMap().remove(String.valueOf(id)); } }
import mydlq.club.example.entity.UserInfo; import mydlq.club.example.service.UserInfoService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping public class UserInfoController { @Autowired private 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"; } }
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.2.RELEASE</version> </parent> <groupId>mydlq.club</groupId> <artifactId>springboot-caffeine-cache-example-2</artifactId> <version>0.0.1</version> <name>springboot-caffeine-cache-example-2</name> <description>Demo project for Spring Boot caffeine</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
@Configuration public class CacheConfig { /** * 配置緩存管理器 * * @return 緩存管理器 */ @Bean("caffeineCacheManager") public CacheManager cacheManager() { CaffeineCacheManager cacheManager = new CaffeineCacheManager(); cacheManager.setCaffeine(Caffeine.newBuilder() // 設置最後一次寫入或訪問後通過固定時間過時 .expireAfterAccess(60, TimeUnit.SECONDS) // 初始的緩存空間大小 .initialCapacity(100) // 緩存的最大條數 .maximumSize(1000)); return cacheManager; } }
@Data @ToString public class UserInfo { private Integer id; private String name; private String sex; private Integer age; }
服務接口
import mydlq.club.example.entity.UserInfo; 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); }
服務實現類
import lombok.extern.slf4j.Slf4j; import mydlq.club.example.entity.UserInfo; import mydlq.club.example.service.UserInfoService; 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; @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); } }
import mydlq.club.example.entity.UserInfo; import mydlq.club.example.service.UserInfoService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping public class UserInfoController { @Autowired private 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"; } }
參考地址:
https://www.jianshu.com/p/c72fb0c787fc
http://www.javashuo.com/article/p-apxfgrkx-nz.html
https://github.com/my-dlq/blog-example/tree/master/springboot/springboot-caffeine-cache-example
近期熱文推薦:
1.Java 15 正式發佈, 14 個新特性,刷新你的認知!!
2.終於靠開源項目弄到 IntelliJ IDEA 激活碼了,真香!
3.我用 Java 8 寫了一段邏輯,同事直呼看不懂,你試試看。。
以爲不錯,別忘了隨手點贊+轉發哦!