Redis
是一款開源的,使用 C 開發的高性能內存 Key/Value 數據庫,支持 String、Set、Hash、List、Stream 等等數據類型。它被廣泛用于緩存、消息隊列、實時分析、計數器和排行榜等場景。基本上是當代應用中必不可少的軟件!
Spring Boot 對 Redis 提供了開箱即用的組件:spring-boot-starter-data-redis
。通過這個 starter,我們只需要幾行簡單的配置就可以快速地在 Spring Boot 中整合、使用 Redis。
Spring Boot 整合 Redis
Maven 依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>
除了 spring-boot-starter-data-redis
外,還添加了 commons-pool2
依賴,是因為我們需要使用到連接池。
配置屬性
只需要在 application.yaml | properties
中配置如下常用的基本屬性即可:
spring:redis:# 連接地址host: "localhost"# 端口port: 6379# 數據庫database: 0# 用戶名,如果有# username:# 密碼,如果有# password:# 連接超時connect-timeout: 5s# 讀超時timeout: 5s# Lettuce 客戶端的配置lettuce:# 連接池配置pool:# 最小空閑連接min-idle: 0# 最大空閑連接max-idle: 8# 最大活躍連接max-active: 8# 從連接池獲取連接 最大超時時間,小于等于0則表示不會超時max-wait: -1ms
「注意,如果你使用的 不是 spring boot 2.x ,上述配置的命名空間 不應該是 spring.redis
而是 spring.data.redis
」。
使用 Jedis 客戶端
Spring Data Redis 默認使用 Lettuce
作為 Redis 客戶端。
官方還對 Jedis 提供了支持,你可以根據你的喜好進行選擇。
當然推薦在項目中使用 lettuce
客戶端,因為它是基于 Netty 開發,支持非阻塞式 IO,性能會更好。
要替換為 Jedis,首先需要從 spring-boot-starter-data-redis
排除 lettuce
,并且添加 jedis
依賴:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><exclusions><exclusion><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId></exclusion></exclusions></dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId>
</dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>
然后修改配置文件,把 lettuce
配置替換為 jedis
配置即可:
spring:redis:# jedis客戶端的配置jedis:# 連接池配置pool:# 最小空閑連接min-idle: 0# 最大空閑連接max-idle: 8# 最大活躍連接max-active: 8# 從連接池獲取連接 最大超時時間,小于等于0則表示不會超時max-wait: -1ms
使用 StringRedisTemplate
配置就緒后,StringRedisTemplate
已經可用,你可以在任何地方注入、使用:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class DemoApplicationTests {static final Logger logger = LoggerFactory.getLogger(DemoApplicationTests.class);// 注入 StringRedisTemplate@AutowiredStringRedisTemplate stringRedisTemplate;@Testpublic void test() {// 設置this.stringRedisTemplate.opsForValue().set("title", "spring 中文網", Duration.ofMinutes(5));// 讀取String val = this.stringRedisTemplate.opsForValue().get("title");logger.info("value={}", val);}
}
對于 StringRedisTemplate
更完整的方法列表,你可以參閱其 java doc。
自定義 RedisTemplate
如果基本的 StringRedisTemplate
不能滿足你的需求,你也可以自定義 RedisTemplate
實現。
例如,我們想要自定義一個 JsonRedisTemplate
,用于把任意 Java 對象序列化為 json 數據存儲到 Redis,并且也能夠把 Redis 中的 json 數據反序列化為任意 Java 對象。
如下:
package com.zcdf.school.components;import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;@Component
public class JsonRedisTemplate extends RedisTemplate<String, Object> {public JsonRedisTemplate(RedisConnectionFactory redisConnectionFactory) {// 構造函數注入 RedisConnectionFactory,設置到父類super.setConnectionFactory(redisConnectionFactory);Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);ObjectMapper objectMapper = new ObjectMapper();objectMapper.registerModule(new JavaTimeModule());serializer.setObjectMapper(objectMapper);// String 類型的 key/value 序列化super.setKeySerializer(StringRedisSerializer.UTF_8);super.setValueSerializer(serializer);// Hash 類型的 key/value 序列化super.setHashKeySerializer(StringRedisSerializer.UTF_8);super.setHashValueSerializer(serializer);}
}
首先,繼承 RedisTemplate<K,V>
,泛型 K
表示 Redis Key 類型,一般都是 String
,泛型 V
表示 Redis Value 類型,既然我們需要的是一個通用的 JSON Template,所以設置為 Object
,Value 值可以是任意對象。
在構造函數中注入 RedisConnectionFactory
設置到父類,「這是必須的」。
然后創建GenericJackson2JsonRedisSerializer
實例,它是基于 Jackson 的 RedisSerializer
實現,用于任意 Java 對象和 JSON 字符串之間的序列化/反序列化。使用該實例作為普通 Value 和 Hash Value 的序列化/反序列化器。注意,因為序列化的對象可能包含了 java.time
類型的日期字段,如:LocalTime
、LocalDate
以及 LocalDateTime
,所以需要注冊 JavaTimeModule
。
創建測試類進行測試。如下:
@GetMapping("/eee")public int www() {System.out.println("測試方法開始執行:");// MapMap<String, Object> map = new HashMap<>();map.put("name", "wtt");map.put("url", "https://*****.cn");map.put("createAt", LocalDateTime.now());jsonRedisTemplate.opsForValue().set("key1-map", map, Duration.ofMinutes(5));Map<String, Object> map2 = (Map<String, Object>) jsonRedisTemplate.opsForValue().get("key1-map");System.out.println(map2);// Hash// 設置this.jsonRedisTemplate.opsForHash().put("key2-hash", "app", map);// 讀取map = (Map<String, Object>) this.jsonRedisTemplate.opsForHash().get("key2-hash", "app");log.info("map={}", map);return 0;}
我們創建了一個 Map<String, Object>
對象,存儲了 2 個 String
和一個 LocalDateTime
字段。然后使用 JsonRedisTemplate
把它存儲為普通 Value 和 Hash Value。
存儲成功后,再進行讀取,反序列化為原來的 Map<String, Object>
對象。
運行測試,執行日志如下:
測試方法開始執行:
{name=wtt, url=https://*****.cn, createAt=[2024, 5, 21, 15, 22, 40, 807000000]}
2024-05-21 15:22:41.079 INFO 7316 --- [nio-8888-exec-1] com.zcdf.school.controller.Testwtt : map={name=wtt, url=https://*****.cn, createAt=[2024, 5, 21, 15, 22, 40, 807000000]}
我們發現,序列化為 JSON、反序列化為對象都沒問題。
好文分享,一起努力加油。