SpringBoot中整合Redis(緩存篇)
實際開發中緩存處理是必須的,不可能我們每次客戶端去請求一次服務器,服務器每次都要去數據庫中進行查找,為什么要使用緩存?說到底是為了提高系統的運行速度。將用戶頻繁訪問的內容存放在離用戶最近,訪問速度最快的地方,提高用戶的響應速度,今天先來講下在springboot中整合redis的詳細步驟。
一、安裝
redis下載地址:
首先要在本地安裝一個redis程序,安裝過程十分簡單(略過),安裝完成后進入到redis文件夾中可以看到如下:
點擊redis-server.exe開啟redis服務,可以看到如下圖所示即代表開啟redis服務成功:
那么我們可以開啟redis客戶端進行測試:
二、整合到springboot
1、在項目中加入redis依賴,pom文件中添加如下:
- <!-- 整合Redis緩存支持 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-redis</artifactId>
- </dependency>
2、在application.yml中添加redis配置:
- ##默認密碼為空
- redis:
- host: 127.0.0.1
- # Redis服務器連接端口
- port: 6379
- jedis:
- pool:
- #連接池最大連接數(使用負值表示沒有限制)
- max-active: 100
- # 連接池中的最小空閑連接
- max-idle: 10
- # 連接池最大阻塞等待時間(使用負值表示沒有限制)
- max-wait: 100000
- # 連接超時時間(毫秒)
- timeout: 5000
- #默認是索引為0的數據庫
- database: 0
3、新建RedisConfiguration配置類,繼承CachingConfigurerSupport,@EnableCaching開啟注解
- @Configuration
- @EnableCaching
- public class RedisConfiguration extends CachingConfigurerSupport {
- /**
- * 自定義生成key的規則
- */
- @Override
- public KeyGenerator keyGenerator() {
- return new KeyGenerator() {
- @Override
- public Object generate(Object o, Method method, Object... objects) {
- //格式化緩存key字符串
- StringBuilder sb = new StringBuilder();
- //追加類名
- sb.append(o.getClass().getName());
- //追加方法名
- sb.append(method.getName());
- //遍歷參數并且追加
- for (Object obj : objects) {
- sb.append(obj.toString());
- }
- System.out.println("調用Redis緩存Key : " + sb.toString());
- return sb.toString();
- }
- };
- }
- /**
- * 采用RedisCacheManager作為緩存管理器
- * @param connectionFactory
- */
- @Bean
- public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
- RedisCacheManager redisCacheManager = RedisCacheManager.create(connectionFactory);
- return redisCacheManager;
- }
- @Bean
- public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
- ////解決鍵、值序列化問題
- StringRedisTemplate template = new StringRedisTemplate(factory);
- Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
- ObjectMapper om = new ObjectMapper();
- om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
- om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
- jackson2JsonRedisSerializer.setObjectMapper(om);
- template.setValueSerializer(jackson2JsonRedisSerializer);
- template.afterPropertiesSet();
- return template;
- }
- }
4、創建自定義的接口來定義需要的redis的功能
- /**
- * K 指以hash結構操作時 鍵類型
- * T 為數據實體 應實現序列化接口,并定義serialVersionUID * RedisTemplate 提供了五種數據結構操作類型 hash / list / set / zset / value
- * 方法命名格式為 數據操作類型 + 操作 如 hashPut 指以hash結構(也就是map)想key添加鍵值對
- */
- public interface RedisHelper<HK, T> {
- /**
- * Hash結構 添加元素 * @param key key * @param hashKey hashKey * @param domain 元素
- */
- void hashPut(String key, HK hashKey, T domain);
- /**
- * Hash結構 獲取指定key所有鍵值對 * @param key * @return
- */
- Map<HK, T> hashFindAll(String key);
- /**
- * Hash結構 獲取單個元素 * @param key * @param hashKey * @return
- */
- T hashGet(String key, HK hashKey);
- void hashRemove(String key, HK hashKey);
- /**
- * List結構 向尾部(Right)添加元素 * @param key * @param domain * @return
- */
- Long listPush(String key, T domain);
- /**
- * List結構 向頭部(Left)添加元素 * @param key * @param domain * @return
- */
- Long listUnshift(String key, T domain);
- /**
- * List結構 獲取所有元素 * @param key * @return
- */
- List<T> listFindAll(String key);
- /**
- * List結構 移除并獲取數組第一個元素 * @param key * @return
- */
- T listLPop(String key);
- /**
- * 對象的實體類
- * @param key
- * @param domain
- * @return
- */
- void valuePut(String key, T domain);
- /**
- * 獲取對象實體類
- * @param key
- * @return
- */
- T getValue(String key);
- void remove(String key);
- /**
- * 設置過期時間 * @param key 鍵 * @param timeout 時間 * @param timeUnit 時間單位
- */
- boolean expirse(String key, long timeout, TimeUnit timeUnit);
- }
下面是創建RedisHelperImpl進行接口的實現
- @Service("RedisHelper")
- public class RedisHelperImpl<HK, T> implements RedisHelper<HK, T> {
- // 在構造器中獲取redisTemplate實例, key(not hashKey) 默認使用String類型
- private RedisTemplate<String, T> redisTemplate;
- // 在構造器中通過redisTemplate的工廠方法實例化操作對象
- private HashOperations<String, HK, T> hashOperations;
- private ListOperations<String, T> listOperations;
- private ZSetOperations<String, T> zSetOperations;
- private SetOperations<String, T> setOperations;
- private ValueOperations<String, T> valueOperations;
- // IDEA雖然報錯,但是依然可以注入成功, 實例化操作對象后就可以直接調用方法操作Redis數據庫
- @Autowired
- public RedisHelperImpl(RedisTemplate<String, T> redisTemplate) {
- this.redisTemplate = redisTemplate;
- this.hashOperations = redisTemplate.opsForHash();
- this.listOperations = redisTemplate.opsForList();
- this.zSetOperations = redisTemplate.opsForZSet();
- this.setOperations = redisTemplate.opsForSet();
- this.valueOperations = redisTemplate.opsForValue();
- }
- @Override
- public void hashPut(String key, HK hashKey, T domain) {
- hashOperations.put(key, hashKey, domain);
- }
- @Override
- public Map<HK, T> hashFindAll(String key) {
- return hashOperations.entries(key);
- }
- @Override
- public T hashGet(String key, HK hashKey) {
- return hashOperations.get(key, hashKey);
- }
- @Override
- public void hashRemove(String key, HK hashKey) {
- hashOperations.delete(key, hashKey);
- }
- @Override
- public Long listPush(String key, T domain) {
- return listOperations.rightPush(key, domain);
- }
- @Override
- public Long listUnshift(String key, T domain) {
- return listOperations.leftPush(key, domain);
- }
- @Override
- public List<T> listFindAll(String key) {
- if (!redisTemplate.hasKey(key)) {
- return null;
- }
- return listOperations.range(key, 0, listOperations.size(key));
- }
- @Override
- public T listLPop(String key) {
- return listOperations.leftPop(key);
- }
- @Override
- public void valuePut(String key, T domain) {
- valueOperations.set(key, domain);
- }
- @Override
- public T getValue(String key) {
- return valueOperations.get(key);
- }
- @Override
- public void remove(String key) {
- redisTemplate.delete(key);
- }
- @Override
- public boolean expirse(String key, long timeout, TimeUnit timeUnit) {
- return redisTemplate.expire(key, timeout, timeUnit);
- }
- }
三、測試
編寫TestRedis類進行測試
- @RunWith(SpringRunner.class)
- @SpringBootTest
- public class TestRedis {
- @Autowired
- private StringRedisTemplate stringRedisTemplate;
- @Autowired
- private RedisTemplate redisTemplate;
- @Autowired
- private RedisHelperImpl redisHelper;
- @Test
- public void test() throws Exception{
- // 基本寫法
- // stringRedisTemplate.opsForValue().set("aaa","111");
- // Assert.assertEquals("111",stringRedisTemplate.opsForValue().get("aaa"));
- // System.out.println(stringRedisTemplate.opsForValue().get("aaa"));
- Author user=new Author();
- user.setName("Alex");
- user.setIntro_l("不會打籃球的程序不是好男人");
- redisHelper.valuePut("aaa",user);
- System.out.println(redisHelper.getValue("aaa"));
- }
- @Test
- public void testObj() throws Exception {
- Author user=new Author();
- user.setName("Jerry");
- user.setIntro_l("不會打籃球的程序不是好男人!");
- ValueOperations<String, Author> operations=redisTemplate.opsForValue();
- operations.set("502", user);
- Thread.sleep(500);
- boolean exists=redisTemplate.hasKey("502");
- if(exists){
- System.out.println(redisTemplate.opsForValue().get("502"));
- }else{
- System.out.println("exists is false");
- }
- // Assert.assertEquals("aa", operations.get("com.neo.f").getUserName());
- }
- }
運行TestRedis測試類,結果如下:
注意:如果在RedisConfiguration中不配置redisTemplate(RedisConnectionFactory factory)注解,會造成鍵、值的一個序列化問題,有興趣的可以去試一下。序列化:序列化框架的選型和比對
四、項目實戰
首先需要在程序的入口處Application中添加@EnableCaching開啟緩存的注解
- @EnableCaching //開啟緩存
- @SpringBootApplication
- public class PoetryApplication {
- public static void main(String[] args) {
- SpringApplication.run(PoetryApplication.class, args);
- }
- }
上面的redis相關寫法是我們自定義設置并獲取的,那么我們經常要在訪問接口的地方去使用redis進行緩存相關實體對象以及集合等,那么我們怎么實現呢?
比如我現在想在AuthorController中去緩存作者相關信息的緩存數據,該怎么辦呢?如下:
- @RestController
- @RequestMapping(value = "/poem")
- public class AuthorController {
- private final static Logger logger = LoggerFactory.getLogger(AuthorController.class);
- @Autowired
- private AuthorRepository authorRepository;
- @Cacheable(value="poemInfo") //自動根據方法生成緩存
- @PostMapping(value = "/poemInfo")
- public Result<Author> author(@RequestParam("author_id") int author_id, @RequestParam("author_name")String author_name) {
- if(StringUtils.isEmpty(author_id) || StringUtils.isEmpty(author_name)){
- return ResultUtils.error(ResultCode.INVALID_PARAM_EMPTY);
- }
- Author author;
- Optional<Author> optional = authorRepository.getAuthorByIdAndName(author_id, author_name);
- if (optional.isPresent()) {
- author = optional.get();
- //通過\n或者多個空格 進行過濾去重
- if (!StringUtils.isEmpty(author.getIntro_l())) {
- String s = author.getIntro_l();
- String intro = s.split("\\s +")[0];
- author.setIntro_l(intro);
- }
- } else {
- return ResultUtils.error(ResultCode.NO_FIND_THINGS);
- }
- return ResultUtils.ok(author);
- }
- }
這里 @Cacheable(value="poemInfo")這個注解的意思就是自動根據方法生成緩存,value就是緩存下來的key。到這里我們就已經把redis整合到了springboot中了