Spring Boot 集成 Guava Cache 實現緩存機制
Guava Cache 是一個全內存的本地緩存實現,而且提供了線程安全機制,相比於數據庫或 Redis 存儲,訪問內存中的數據會更加高效。
Guava 官網介紹,下面的這幾種情況可以考慮使用 Guava Cache:
-
願意消耗一些內存空間來提升速度。
-
預料到某些鍵會被多次查詢。
-
緩存中存放的數據總量不會超出內存容量。
所以,可以將頻繁用到的少量數據存儲到 Guava Cache 中,以提高程序性能。下面我們來看看 Guava Cache 具體用法。
添加依賴
在 pom.xml 中添加 spring-boot-starter-cache
和 guava
依賴。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--guava 依賴-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.0.1-jre</version>
</dependency>
準備數據
模擬數據庫的數據
/**
* 數據工廠,模擬數據庫的數據
*
* @author star
**/
public class DataFactory {
private DataFactory() {
}
private static List<UserDto> userDtoList;
static {
// 初始化集合
userDtoList = new ArrayList<>();
UserDto user = null;
for (int i = 0; i < 5; i++) {
user = new UserDto();
user.setName("star" + i);
user.setAge(23);
userDtoList.add(user);
}
}
public static List<UserDto> getUserDaoList() {
return userDtoList;
}
}
創建 Guava Cache 配置類
Guava Cache 配置比較簡潔,下面配置了緩存數據的過期時間是 10s,最大緩存容量是 1000 個。
@Configuration
@EnableCaching
public class GuavaCacheConfig {
/**
* 設置緩存管理器
*/
@Bean
public CacheManager cacheManager(){
GuavaCacheManager cacheManager = new GuavaCacheManager();
cacheManager.setCacheBuilder(CacheBuilder.newBuilder()
// 緩存過期時間
.expireAfterWrite(10, TimeUnit.SECONDS)
// 緩存最大容量是 1000
.maximumSize(1000)
);
return cacheManager;
}
}
Guava Cache 除了代碼中提到的設置緩存過期時間的策略外,還有其他的策略。下面是 Guava Cache 設置緩存過期時間的策略:
-
expireAfterAccess: 當緩存項在指定的時間段內沒有被讀或寫就會被回收。
-
expireAfterWrite:當緩存項在指定的時間段內沒有更新就會被回收,如果我們認爲緩存數據在一段時間後數據不再可用,那麼可以使用該種策略。
-
refreshAfterWrite:當緩存項上一次更新操作之後的多久會被刷新。
編寫業務代碼
- 編寫 DAO 層
/**
* UserRepository
*
* @author star
**/
@Repository
public class UserRepository {
/**
* 獲取用戶信息(此處是模擬的數據)
*/
public UserDto getUserByName(String username) {
UserDto user = getUserFromList(username);
return user;
}
/**
* 從模擬的數據集合中篩選 username 的數據
*/
private UserDto getUserFromList(String username) {
List<UserDto> userDaoList = DataFactory.getUserDaoList();
for (UserDto user : userDaoList) {
if (Objects.equals(user.getName(), username)) {
return user;
}
}
return null;
}
}
- 編寫 Service 層
/**
* UserService
*
* @author star
**/
@Service
@CacheConfig(cacheNames = "guavaCache") // 聲明緩存的名稱
public class UserService {
@Autowired
private UserRepository userRepository;
@Cacheable(key = "#name")
public UserDto getUserByName(String name) {
System.out.println("從數據庫中獲取數據,而不是讀取緩存");
return userRepository.getUserByName(name);
}
}
由於在上一篇 Spring Boot 緩存技術 已經對緩存用法做了詳細說明,這裏就簡單介紹一下:
-
@Cacheable
: 主要針對方法配置,能夠根據方法的請求參數對其結果進行緩存。同時在查詢時,會先從緩存中獲取,若不存在纔再發起對數據庫的訪問。 -
@CachePut
:配置於方法上時,能夠根據參數定義條件來進行緩存,其與 @Cacheable 不同的是,它不會去檢查緩存中是否存在之前執行過的結果,而是每次都會執行該方法,並將執行結果以鍵值對的形式存入指定的緩存中,所以主要用於數據新增和修改操作上。 -
@CacheEvict
:配置於方法上時,表示從緩存中移除相應數據。 -
編寫 Controller 層
/**
* UserResource
*
* @author star
**/
@RestController
@RequestMapping("/api")
public class UserResource {
@Autowired
private UserService userService;
@Autowired
private CacheManager cacheManager;
@GetMapping("/users/{name}")
public ResponseEntity<UserDto> getUser(@PathVariable String name) {
System.out.println("==================");
UserDto user = userService.getUserByName(name);
System.out.println(cacheManager.toString());
return ResponseEntity.ok(user);
}
}
演示
通過多次向接口 http://localhost:8080/api/users/star1
GET 數據來觀察效果:
可以看到緩存的啓用和效果如下所示:
後記
由於自身能力有限,若有錯誤或者不當之處,還請大家批評指正,一起學習交流!
GitHub 源碼地址:springboot-guava-cache