springboot整合spring @Cache和Redis
轉載請註明出處:https://www.cnblogs.com/wenjunwei/p/10779450.html
spring基於註解的快取
對於快取宣告,spring的快取提供了一組java註解:
- @Cacheable:觸發快取寫入。
- @CacheEvict:觸發快取清除。
- @CachePut:更新快取(不會影響到方法的執行)。
- @Caching:重新組合要應用於方法的多個快取操作。
- @CacheConfig:設定類級別上共享的一些常見快取設定。
@Cacheable註解
顧名思義,@Cacheable可以用來進行快取的寫入,將結果儲存在快取中,以便於在後續呼叫的時候可以直接返回快取中的值,而不必再執行實際的方法。 最簡單的使用方式,註解名稱=快取名稱,使用例子如下:
@Cacheable("books") public Book findBook(ISBN isbn) {...}
一個方法可以對應兩個快取名稱,如下:
@Cacheable({"books", "isbns"}) public Book findBook(ISBN isbn) {...}
@Cacheable的快取名稱是可以配置動態引數的,比如選擇傳入的引數,如下: (以下示例是使用SpEL宣告,如果您不熟悉SpEL,可以閱讀Spring Expression Language)
@Cacheable(cacheNames="books", key="#isbn") public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) @Cacheable(cacheNames="books", key="#isbn.rawNumber") public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) @Cacheable(cacheNames="books", key="T(someType).hash(#isbn)") public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
@Cacheable還可以設定根據條件判斷是否需要快取
- condition:取決於給定的引數是否滿足條件
- unless:取決於返回值是否滿足條件
以下是一個簡單的例子:
@Cacheable(cacheNames="book", condition="#name.length() < 32") public Book findBook(String name) @Cacheable(cacheNames="book", condition="#name.length() < 32", unless="#result.hardback") public Book findBook(String name)
@Cacheable還可以設定:keyGenerator(指定key自動生成方法),cacheManager(指定使用的快取管理),cacheResolver(指定使用快取的解析器)等,這些引數比較適合全域性設定,這裡就不多做介紹了。
@CachePut註解
@CachePut:當需要更新快取而不干擾方法的執行時 ,可以使用該註解。也就是說,始終執行該方法,並將結果放入快取,註解引數與@Cacheable相同。 以下是一個簡單的例子:
@CachePut(cacheNames="book", key="#isbn") public Book updateBook(ISBN isbn, BookDescriptor descriptor)
通常強烈建議不要對同一方法同時使用@CachePut和@Cacheable註解,因為它們具有不同的行為。可能會產生不可思議的BUG哦。
@CacheEvict註解
@CacheEvict:刪除快取的註解,這對刪除舊的資料和無用的資料是非常有用的。這裡還多了一個引數(allEntries),設定allEntries=true時,可以對整個條目進行批量刪除。 以下是個簡單的例子:
@CacheEvict(cacheNames="books") public void loadBooks(InputStream batch) //對cacheNames進行批量刪除 @CacheEvict(cacheNames="books", allEntries=true) public void loadBooks(InputStream batch)
@Caching註解
@Caching:在使用快取的時候,有可能會同時進行更新和刪除,會出現同時使用多個註解的情況.而@Caching可以實現。 以下是個簡單的例子:
@Caching(evict = { @CacheEvict("primary"), @CacheEvict(cacheNames="secondary", key="#p0") }) public Book importBooks(String deposit, Date date)
@CacheConfig註解
@CacheConfig:快取提供了許多的註解選項,但是有一些公用的操作,我們可以使用@CacheConfig在類上進行全域性設定。 以下是個簡單的例子:
@CacheConfig("books") public class BookRepositoryImpl implements BookRepository { @Cacheable public Book findBook(ISBN isbn) {...} }
可以共享快取名稱,統一配置KeyGenerator,CacheManager,CacheResolver。
例項
來看看我們在springboot中怎麼使用redis來作為快取吧.
為spring cache配置redis作為快取
1.在pom.xml引入redis依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
2.springboot整合redis配置檔案(在本地啟動的redis),在springboot中使用redis,只要配置檔案寫有redis配置,程式碼就可以直接使用了。
spring: redis: database: 0 # Database index used by the connection factory. url: redis://user:@127.0.0.1:6379 # Connection URL. Overrides host, port, and password. User is ignored. Example: redis://user:[email protected]:6379 host: 127.0.0.1 # Redis server host. password: # Login password of the redis server. port: 6379 # Redis server port. ssl: false # Whether to enable SSL support. timeout: 5000 # Connection timeout.
3.redis快取配置類CacheConfig,這裡對spring的快取進行了配置,包括KeyGenerator,CacheResolver,CacheErrorHandler,CacheManager,還有redis序列化方式。
/** * @author wwj */ @Configuration public class CacheConfig extends CachingConfigurerSupport { @Resource private RedisConnectionFactory factory; /** * 自定義生成redis-key * * @return */ @Override @Bean public KeyGenerator keyGenerator() { return (o, method, objects) -> { StringBuilder sb = new StringBuilder(); sb.append(o.getClass().getName()).append("."); sb.append(method.getName()).append("."); for (Object obj : objects) { sb.append(obj.toString()); } System.out.println("keyGenerator=" + sb.toString()); return sb.toString(); }; } @Bean public RedisTemplate<Object, Object> redisTemplate() { RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(factory); GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); redisTemplate.setKeySerializer(genericJackson2JsonRedisSerializer); redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer); return redisTemplate; } @Bean @Override public CacheResolver cacheResolver() { return new SimpleCacheResolver(cacheManager()); } @Bean @Override public CacheErrorHandler errorHandler() { // 用於捕獲從Cache中進行CRUD時的異常的回撥處理器。 return new SimpleCacheErrorHandler(); } @Bean @Override public CacheManager cacheManager() { RedisCacheConfiguration cacheConfiguration = defaultCacheConfig() .disableCachingNullValues() .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); return RedisCacheManager.builder(factory).cacheDefaults(cacheConfiguration).build(); } }
程式碼使用
測試@Cacheable方法
@Test public void findUserTest() { for (int i = 0; i < 3; i++) { System.out.println("第" + i + "次"); User user = userService.findUser(); System.out.println(user); } } @Override @Cacheable(value = {"valueName", "valueName2"}, key = "'keyName1'") public User findUser() { System.out.println("執行方法..."); return new User("id1", "張三", "深圳", "1234567", 18); }
執行結果
只有一次輸出了'執行方法...',後面直接從快取獲取,不會再進入方法。
第0次 執行方法... User{id='id1', name='張三', address='深圳', tel='1234567', age=18} 第1次 User{id='id1', name='張三', address='深圳', tel='1234567', age=18} 第2次 User{id='id1', name='張三', address='深圳', tel='1234567', age=18}
測試@CachePut方法:對快取進行了修改
@Test public void updateUserTest() { userService.updateUser(); User user = userService.findUser(); System.out.println(user); } @Override @CachePut(value = "valueName", key = "'keyName1'") public User updateUser() { System.out.println("更新使用者..."); return new User("id1", "李四", "北京", "1234567", 18); }
執行結果
對快取進行了更新,獲取值的時候取了新的值
更新使用者... User{id='id1', name='李四', address='北京', tel='1234567', age=18}
測試@CacheEvict方法:快取被清空,再次findUser的時候又重新執行了方法。
@Test public void clearUserTest() { userService.clearUser(); User user = userService.findUser(); System.out.println(user); } @Override @CacheEvict(value = "valueName",allEntries = true) public void clearUser() { System.out.println("清除快取..."); }
執行結果
這裡清除了快取,為什麼還是沒有執行方法呢?因為這個方法我們定了兩個value值,清了一個還有一個
清除快取... User{id='id1', name='張三', address='深圳', tel='1234567', age=18}
最後貼一下程式碼吧
User.java
package com.wwj.springboot.model; import java.io.Serializable; /** * @author wwj */ public class User implements Serializable { public User() { } private String id; private String name; private String address; private String tel; private Integer age; //省略get,set,tostring }
CacheTest.java
package com.wwj.springboot.cache; import com.wwj.springboot.model.User; import com.wwj.springboot.service.UserService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cache.annotation.EnableCaching; import org.springframework.test.context.junit4.SpringRunner; import javax.annotation.Resource; /** * @author wwj */ @RunWith(SpringRunner.class) @SpringBootTest @EnableCaching public class CacheTest { @Resource private UserService userService; @Test public void findUserTest() { for (int i = 0; i < 3; i++) { System.out.println("第" + i + "次"); User user = userService.findUser(); System.out.println(user); } } @Test public void updateUserTest() { userService.updateUser(); User user = userService.findUser(); System.out.println(user); } @Test public void clearUserTest() { userService.clearUser(); User user = userService.findUser(); System.out.println(user); } }
UserService.java
package com.wwj.springboot.service; import com.wwj.springboot.model.User; import java.util.List; /** * @author wwj */ public interface UserService { /** * 獲取使用者 * @return user */ User findUser(); /** * 更新使用者資訊 * @return user */ User updateUser(); /** * 清除快取的使用者資訊 */ void clearUser(); }
UserServiceImpl.java
package com.wwj.springboot.service.impl; import com.wwj.springboot.model.User; import com.wwj.springboot.service.UserService; 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; /** * @author wwj */ @Service @CacheConfig(cacheNames = "CacheConfigName") public class UserServiceImpl implements UserService { @Override @Cacheable(value = {"valueName", "valueName2"}, key = "'keyName1'") public User findUser() { System.out.println("執行方法..."); return new User("id1", "張三", "深圳", "1234567", 18); } @Override @CachePut(value = "valueName", key = "'keyName1'") public User updateUser() { System.out.println("更新使用者..."); return new User("id1", "李四", "北京", "1234567", 18); } @Override @CacheEvict(value = "valueName",allEntries = true) public void clearUser() { System.out.println("清除快取..."); } }
本文歡迎各位轉載,但是轉載文章之後必須在文章開頭給出原文連結。感謝您的閱讀,如果您覺得閱讀本文對您有幫助,請點個“推薦”支援一下。
&n