5.3?自定義Redis緩存序列化機(jī)制
?????????剛剛完成了Spring Boot整合Redis進(jìn)行了數(shù)據(jù)的緩存管理,但緩存管理的實(shí)體類數(shù)據(jù)使用的是JDK序列化方式,不便于使用可視化管理工具進(jìn)行查看和管理。

接下來分別針對(duì)基于注解的Redis緩存實(shí)現(xiàn)和基于API的Redis緩存實(shí)現(xiàn)中的數(shù)據(jù)序列化機(jī)制進(jìn)行介紹,并自定義JSON格式的數(shù)據(jù)序列化方式進(jìn)行數(shù)據(jù)緩存管理?
5.3.1?自定義RedisTemplate
1.Redis API默認(rèn)序列化機(jī)制
?????????基于API的Redis緩存實(shí)現(xiàn)是使用RedisTemplate模板進(jìn)行數(shù)據(jù)緩存操作的,這里打開RedisTemplate類,查看該類的源碼信息?
```java
public class RedisTemplate<K, V>
extends RedisAccessor
???????????????????????????????? implementsRedisOperations, BeanClassLoaderAware {
?????? //聲明了key、value的各種序列化方式,初始值為空
???@Nullable
???private RedisSerializer keySerializer = null;
???@Nullable
???private RedisSerializer valueSerializer = null;
??? @Nullable
???private RedisSerializer hashKeySerializer = null;
???@Nullable
???private RedisSerializer hashValueSerializer = null;
?????? ...
?????? //進(jìn)行默認(rèn)序列化方式設(shè)置,設(shè)置為JDK序列化方式
???public void afterPropertiesSet() {
???????super.afterPropertiesSet();
???????boolean defaultUsed = false;
???????if(this.defaultSerializer == null) {
???????????this.defaultSerializer = new JdkSerializationRedisSerializer(
????????????? ?? this.classLoader !=null?this.classLoader:this.getClass().getClassLoader());
???????}
????????????? ...
??? }
?????? ...
}
```
?????????從上述RedisTemplate核心源碼可以看出,在RedisTemplate內(nèi)部聲明了緩存數(shù)據(jù)key、value的各種序列化方式,且初始值都為空;在afterPropertiesSet()方法中,判斷如果默認(rèn)序列化參數(shù)defaultSerializer為空,將數(shù)據(jù)的默認(rèn)序列化方式設(shè)置為JdkSerializationRedisSerializer?
??????? ??? 根據(jù)上述源碼信息的分析,可以得到以下兩個(gè)重要的結(jié)論:
(1)使用RedisTemplate進(jìn)行Redis數(shù)據(jù)緩存操作時(shí),內(nèi)部默認(rèn)使用的是JdkSerializationRedisSerializer序列化方式,所以進(jìn)行數(shù)據(jù)緩存的實(shí)體類必須實(shí)現(xiàn)JDK自帶的序列化接口(例如Serializable);
(2)使用RedisTemplate進(jìn)行Redis數(shù)據(jù)緩存操作時(shí),如果自定義了緩存序列化方式defaultSerializer,那么將使用自定義的序列化方式。
?????????另外,在RedisTemplate類源碼中,看到的緩存數(shù)據(jù)key、value的各種序列化類型都是RedisSerializer。進(jìn)入RedisSerializer源碼查看RedisSerializer支持的序列化方式(進(jìn)入該類后,使用Ctrl+Alt+左鍵單擊類名查看)?

?????????可以看出,RedisSerializer是一個(gè)Redis序列化接口,默認(rèn)有6個(gè)實(shí)現(xiàn)類,這6個(gè)實(shí)現(xiàn)類代表了6種不同的數(shù)據(jù)序列化方式。其中,JdkSerializationRedisSerializer是JDK自帶的,也是RedisTemplate內(nèi)部默認(rèn)使用的數(shù)據(jù)序列化方式,開發(fā)者可以根據(jù)需要選擇其他支持的序列化方式(例如JSON方式)?
?2.自定義RedisTemplate序列化機(jī)制
?????????在項(xiàng)目中引入Redis依賴后,Spring
Boot提供的RedisAutoConfiguration自動(dòng)配置會(huì)生效。打開RedisAutoConfiguration類,查看內(nèi)部源碼中關(guān)于RedisTemplate的定義方式?
```java
public class RedisAutoConfiguration {
???@Bean
???@ConditionalOnMissingBean(
???????name = {"redisTemplate"}
??? )
???public RedisTemplateredisTemplate(RedisConnectionFactory
?????? ????????????????????????????????redisConnectionFactory) throws UnknownHostException {
???????RedisTemplate template = new RedisTemplate();
???????template.setConnectionFactory(redisConnectionFactory);
???????return template;
??? }
?????? ...
}
```
從上述RedisAutoConfiguration核心源碼中可以看出,在Redis自動(dòng)配置類中,通過Redis連接工廠RedisConnectionFactory初始化了一個(gè)RedisTemplate;該類上方添加了@ConditionalOnMissingBean注解(顧名思義,當(dāng)某個(gè)Bean不存在時(shí)生效),用來表明如果開發(fā)者自定義了一個(gè)名為redisTemplate的Bean,則該默認(rèn)初始化的RedisTemplate不會(huì)生效。
?????????如果想要使用自定義序列化方式的RedisTemplate進(jìn)行數(shù)據(jù)緩存操作,可以參考上述核心代碼創(chuàng)建一個(gè)名為redisTemplate的Bean組件,并在該組件中設(shè)置對(duì)應(yīng)的序列化方式即可?
?????????接下來,在項(xiàng)目中創(chuàng)建名為com.lagou.config的包,在該包下創(chuàng)建一個(gè)Redis自定義配置類RedisConfig,并按照上述思路自定義名為redisTemplate的Bean組件?
```java
@Configuration
public class RedisConfig {
???@Bean
???public RedisTemplate redisTemplate(RedisConnectionFactory
??????????????????????????????????????????????????????????????redisConnectionFactory) {
???????RedisTemplate template = new RedisTemplate();
???????template.setConnectionFactory(redisConnectionFactory);
???????//使用JSON格式序列化對(duì)象,對(duì)緩存數(shù)據(jù)key和value進(jìn)行轉(zhuǎn)換
???????Jackson2JsonRedisSerializer jacksonSeial = newJackson2JsonRedisSerializer(Object.class);
???????//解決查詢緩存轉(zhuǎn)換異常的問題
???????ObjectMapper om = new ObjectMapper();
???????om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
???????om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
???????jacksonSeial.setObjectMapper(om);
???????//設(shè)置RedisTemplate模板API的序列化方式為JSON
???????template.setDefaultSerializer(jacksonSeial);
???????return template;
??? }
}
```
?????????通過@Configuration注解定義了一個(gè)RedisConfig配置類,并使用@Bean注解注入了一個(gè)默認(rèn)名稱為方法名的redisTemplate組件(注意,該Bean組件名稱必須是redisTemplate)。在定義的Bean組件中,自定義了一個(gè)RedisTemplate,使用自定義的Jackson2JsonRedisSerializer數(shù)據(jù)序列化方式;在定制序列化方式中,定義了一個(gè)ObjectMapper用于進(jìn)行數(shù)據(jù)轉(zhuǎn)換設(shè)置?
????**3.效果測(cè)試**
?????????啟動(dòng)項(xiàng)目,項(xiàng)目啟動(dòng)成功后,通過瀏覽器訪問“http://localhost:8080/api/findCommentById?id=3”查詢id為3的用戶評(píng)論信息,并重復(fù)刷新瀏覽器查看同一條數(shù)據(jù)信息?

查看控制臺(tái)打印的SQL查詢語句

可以看出,執(zhí)行findById()方法正確查詢出用戶評(píng)論信息Comment,重復(fù)進(jìn)行同樣的查詢操作,數(shù)據(jù)庫只執(zhí)行了一次SQL語句,這說明定制的Redis緩存生效。
?????????使用Redis客戶端可視化管理工具Redis
Desktop Manager查看緩存數(shù)據(jù) :
<img src="./images/image-20191231170942007.png"
alt="image-20191231170942007" style="zoom:67%;" />
?????????執(zhí)行findById()方法查詢出用戶評(píng)論信息Comment正確存儲(chǔ)到了Redis緩存庫中,且緩存到Redis服務(wù)的數(shù)據(jù)已經(jīng)使用了JSON格式存儲(chǔ)展示,查看和管理也非常方便,說明自定義的Redis API模板工具RedisTemplate生效?
剛學(xué)了拉勾教育的《Java工程師高薪訓(xùn)練營(yíng)》,看到剛學(xué)到的點(diǎn)就回答了。希望拉勾能給我推到想去的公司,目標(biāo):字節(jié)!!