簡介
Spring 定義 CacheManager 和 Cache 接口用來統一不一樣的緩存技術。例如 JCache、 EhCache、 Hazelcast、 Guava、 Redis 等。在使用 Spring 集成 Cache 的時候,咱們須要註冊實現的 CacheManager 的 Bean。Spring Boot 默認使用的是 SimpleCacheConfiguration,即便用 ConcurrentMapCacheManager 來實現的緩存。spring
CacheManager:緩存管理器,管理各類緩存組件
CacheManager | 描述 |
---|---|
SimpleCacheManager | 使用檢點 Collection 來存儲緩存,主要用於測試 |
ConcurrentMapCacheManager | 使用 ConcurrentMap 存儲緩存 |
NoOpCacheManager | 僅用於測試,不會實際存儲緩存 |
EhCacheCacheManager | 使用 EhCache 做爲緩存技術 |
GuavaCacheManager | 使用 Guava 做爲緩存技術 |
HazelcastCacheManager | 使用 Hazelcast 做爲緩存技術 |
JCacheCacheManager | 支持 JCache(JSR-107)標準的實現做爲緩存技術 |
RedisCacheManager | 使用 Redis 做爲緩存技術 |
Cache 註解詳解
1. @CacheConfig
@CacheConfig:主要用於配置該類中會用到的一些共用的緩存配置。
在這裏 @CacheConfig(cacheNames = 「users」):配置了該數據訪問對象中返回的內容將存儲於名爲 users 的緩存對象中,咱們也能夠不使用該註解,直接經過 @Cacheable 本身配置緩存集的名字來定義。數據庫
2. @Cacheable
@Cacheable:主要針對方法配置,可以根據方法的請求參數對其結果進行緩存。同時在查詢時,會先從緩存中獲取,若不存在纔再發起對數據庫的訪問。該註解主要有下面幾個參數:api
- value、cacheNames:兩個等同的參數(cacheNames 爲Spring 4 新增,做爲 value 的別名),用於指定緩存存儲的集合名。因爲 Spring 4 中新增了 @CacheConfig,所以在 Spring 3 中本來必須有的 value 屬性,也成爲非必需項了。
- key:緩存對象存儲在 Map 集合中的 key 值,非必需,缺省按照函數的全部參數組合做爲 key 值,若本身配置需使用 SpEL表 達式,好比:@Cacheable(key = 「#p0」):使用函數第一個參數做爲緩存的 key 值,更多關於 SpEL 表達式的詳細內容可參考官方文檔。
- condition:緩存對象的條件,非必需,也需使用SpEL表達式,只有知足表達式條件的內容纔會被緩存,好比:@Cacheable(key = 「#p0」, condition = 「#p0.length() < 3」),表示只有當第一個參數的長度小於3的時候纔會被緩存,若作此配置上面的AAA用戶就不會被緩存,讀者可自行實驗嘗試。
- unless:另一個緩存條件參數,非必需,需使用 SpEL 表達式。它不一樣於 condition 參數的地方在於它的判斷時機,該條件是在函數被調用以後才作判斷的,因此它能夠經過對 result 進行判斷。
- keyGenerator:用於指定 key 生成器,非必需。若須要指定一個自定義的 key 生成器,咱們須要去實現
org.springframework.cache.interceptor.KeyGenerator
接口,並使用該參數來指定。須要注意的是,該參數與 key 是互斥的。 - cacheManager:用於指定使用哪一個緩存管理器,非必需。只有當有多個時才須要使用。
-
cacheResolver:用於指定使用那個緩存解析器,非必需。需經過
org.springframework.cache.interceptor.CacheResolver
接口來實現本身的緩存解析器,並用該參數指定。數組
3. @CachePut
@CachePut:配置於方法上,可以根據參數定義條件來進行緩存,它與 @Cacheable 不一樣的是,它不會去檢查緩存中是否存在以前執行過的結果,而是每次都會執行該方法,並將執行結果以鍵值對的形式存入緩存中,因此主要用於數據新增和修改操做上。它的參數與 @Cacheable 相似,具體功能可參考上面對 @Cacheable 參數的解析。緩存
4. @CacheEvict
@CacheEvict:配置於函數上,一般用在刪除方法上,用來從緩存中移除相應數據。除了同 @Cacheable 同樣的參數以外,它還有下面兩個參數:app
- allEntries:非必需,默認爲 false。當爲 true 時,會移除全部數據。
- beforeInvocation:非必需,默認爲 false,會在調用方法以後移除數據;當爲 true 時,會在調用方法以前移除數據。
搭建 Spring Boot 默認緩存
1. 開啓緩存支持
在啓動類上添加 @EnableCaching
開啓緩存支持,進行自動掃描。less
@SpringBootApplication @EnableCaching // 開啓緩存功能 public class CacheApplication { public static void main(String[] args) { SpringApplication.run(CacheApplication.class, args); } }
2. 添加 spring-boot-starter-cache 依賴
在 pom.xml 中添加 spring-boot-starter-cache 依賴。函數
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>
3. 準備數據
模擬數據庫數據
/** * 數據工廠,模擬數據庫的數據 * * @author star **/ public class DataFactory { private DataFactory() { } private static List<UserDto> userDtoList; static { // 初始化集合 userDtoList = new ArrayList<>(); UserDto user = null; for (int i = 0; i < 10; i++) { user = new UserDto(); user.setName("star" + i); user.setAge("2" + i); userDtoList.add(user); } } public static List<UserDto> getUserDaoList() { return userDtoList; } }
編寫緩存業務代碼
/** * UserRepository * * @author star **/ @Repository public class UserRepository { /** * 獲取用戶信息(此處是模擬的數據) */ public UserDto getUser(String username) { UserDto user = getUserFromList(username); return user; } /** * 刪除用戶信息 */ public List<UserDto> deleteUser(String username) { List<UserDto> userDaoList = DataFactory.getUserDaoList(); userDaoList.remove(getUserFromList(username)); return userDaoList; } /** * 新增數據 */ public List<UserDto> save(String username) { // 添加到集合 List<UserDto> userDaoList = DataFactory.getUserDaoList(); for (UserDto userDto : userDaoList) { // 不能重複添加相同數據 if (Objects.equals(userDto.getName(), username)) { return userDaoList; } } UserDto user = new UserDto(); user.setName(username); user.setAge("50"); userDaoList.add(user); return userDaoList; } /** * 從模擬的數據集合中篩選 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; } }
/** * UserService * * @author star **/ @Service @CacheConfig(cacheNames = "users")// 指定緩存名稱,在本類中是全局的 public class UserService { @Autowired private UserRepository userRepository; /** * 緩存 key 是 username 的數據到緩存 users 中, * 若是沒有指定 key,則方法參數做爲 key 保存到緩存中 */ @Cacheable(key = "#username") public UserDto getUser(String username) { System.out.println("從數據庫中獲取數據,而不是讀取緩存"); return userRepository.getUser(username); } /** * 新增或更新緩存中的數據 */ @CachePut(key = "#username") public List<UserDto> save(String username) { return userRepository.save(username); } /** * 從緩存 users 中刪除 key 是 username 的數據 */ @CacheEvict(key = "#username") public List<UserDto> deleteUser(String username) { System.out.println("從數據庫中刪除數據,以及緩存中的數據"); return userRepository.deleteUser(username); } }
/** * CacheResource * * @author star **/ @RestController @RequestMapping("/api") public class CacheResource { @Autowired private UserService userService; @GetMapping("/users/{username}") public ResponseEntity<UserDto> getUser(@PathVariable String username) { // 獲取數據 UserDto user = userService.getUser(username); return ResponseEntity.ok(user); } @PutMapping("/users/{username}") public ResponseEntity<List<UserDto>> save(@PathVariable String username) { List<UserDto> userDtoList = userService.save(username); return ResponseEntity.ok(userDtoList); } @DeleteMapping("/users/{username}") public ResponseEntity<List<UserDto>> delete(@PathVariable String username) { List<UserDto> userDtoList = userService.deleteUser(username); return ResponseEntity.ok(userDtoList); } } 啓動服務: 訪問:http://localhost:8080/api/users/star1