SpringBoot結(jié)合Redis實(shí)現(xiàn)序列化的方法詳解
前言
最近在學(xué)習(xí)Spring Boot結(jié)合Redis時(shí)看了一些網(wǎng)上的教程,發(fā)現(xiàn)這些教程要么比較老,要么不知道從哪抄得,運(yùn)行起來(lái)有問(wèn)題。這里分享一下我最新學(xué)到的寫法
默認(rèn)情況下,Spring 為我們提供了一個(gè) RedisTemplate 來(lái)進(jìn)行對(duì) Redis 的操作,但是 RedisTemplate 默認(rèn)配置的是使用Java本機(jī)序列化。
這種序列化方式,對(duì)于操作字符串或數(shù)字來(lái)說(shuō),用起來(lái)還行,但是如果要對(duì)對(duì)象操作,就不是那么的方便了。
所以我們需要配置合適的序列化方式。在 Spring 官方的文檔中,官方也建議了我們使用其他的方式來(lái)進(jìn)行序列化。比如JSON
https://docs.spring.io/spring-data/redis/docs/2.2.5.RELEASE/reference/html/#redis:serializer
配置類
配置 Jackson2JsonRedisSerializer 序列化策略
下面就開始自動(dòng)配置類的書寫
我使用的是 Jackson2JsonRedisSerializer 來(lái)對(duì)對(duì)象進(jìn)行序列化,所以首先需要一個(gè)方法,來(lái)配置 Jackson2JsonRedisSerializer 序列化策略
private Jackson2JsonRedisSerializer<Object> serializer() { // 使用Jackson2JsonRedisSerializer來(lái)序列化和反序列化redis的value值 Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); ObjectMapper objectMapper = new ObjectMapper(); // 指定要序列化的域,field,get和set,以及修飾符范圍,ANY是都有包括private和public objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // 指定序列化輸入的類型,類必須是非final修飾的,final修飾的類,比如String,Integer等會(huì)跑出異常 objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(objectMapper); return jackson2JsonRedisSerializer; }
這里要注意的是
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
這一句,這一句非常的重要,作用是序列化時(shí)將對(duì)象全類名一起保存下來(lái)
設(shè)置之后的序列化結(jié)果如下:
[
"com.buguagaoshu.redis.model.User",
{
"name": "1",
"age": "11",
"message": "牛逼"
}
]
不設(shè)置的話,序列化結(jié)果如下,將無(wú)法反序列化
{
"name": "1",
"age": "11",
"message": "牛逼"
}
一開始,我在網(wǎng)上搜了一下,發(fā)現(xiàn)大多數(shù)教程因?yàn)闀r(shí)間的原因,這一句用的是
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
但當(dāng)我把這段代碼寫入的時(shí)候,發(fā)現(xiàn)Idea提示我
著是一個(gè)過(guò)時(shí)的方法,由于我當(dāng)時(shí)并不知道這句話的意思,就把這段代碼注釋了,覺(jué)得可能沒(méi)什么用,但注釋后在向Redis里寫數(shù)據(jù)的時(shí)候,數(shù)據(jù)會(huì)變成
導(dǎo)致數(shù)據(jù)無(wú)法反序列化。
最后我查看了這個(gè)方法的源碼,找到了
通過(guò)注釋,我得到了這段代碼的最新寫法。
也明白了這段代碼的作用。
配置 RedisTemplate
@Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); // 用Jackson2JsonRedisSerializer來(lái)序列化和反序列化redis的value值 redisTemplate.setValueSerializer(serializer()); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // 使用StringRedisSerializer來(lái)序列化和反序列化redis的key值 redisTemplate.setKeySerializer(stringRedisSerializer); // hash的key也采用String的序列化方式 redisTemplate.setHashKeySerializer(stringRedisSerializer); // hash的value序列化方式采用jackson redisTemplate.setHashValueSerializer(serializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; }
這里就沒(méi)有什么需要注意的了,按照自己的需求,來(lái)配置序列化的方式
配置緩存策略
@Bean public CacheManager cacheManager(RedisConnectionFactory factory) { RedisSerializer<String> redisSerializer = new StringRedisSerializer(); // 配置序列化(解決亂碼的問(wèn)題) RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() // 緩存有效期 .entryTtl(timeToLive) // 使用StringRedisSerializer來(lái)序列化和反序列化redis的key值 .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)) // 使用Jackson2JsonRedisSerializer來(lái)序列化和反序列化redis的value值 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer())) // 禁用空值 .disableCachingNullValues(); return RedisCacheManager.builder(factory) .cacheDefaults(config) .build(); }
測(cè)試代碼
@SpringBootTest public class RedisApplicationTests { @Autowired private RedisTemplate<String, Object> redisTemplate; @Test void contextLoads() throws Exception { User user = new User(); user.setName("15"); user.setAge(20); user.setMessage("牛逼"); redisTemplate.opsForValue().set(user.getName(), user); User getUser = (User) redisTemplate.opsForValue().get(user.getName()); System.out.println(getUser); System.out.println(getUser.getMessage()); } }
再來(lái)查看Redis中的數(shù)據(jù)
數(shù)據(jù)正常,并且系統(tǒng)也能正常的反序列化了。
完整代碼
package com.buguagaoshu.redis.config; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; 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.RedisSerializationContext; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import java.time.Duration; /** * @author Pu Zhiwei {@literal puzhiweipuzhiwei@foxmail.com} * create 2020-03-17 21:08 * 繼承 CachingConfigurerSupport,為了自定義生成 KEY 的策略??梢圆焕^承。 */ @Configuration @EnableCaching public class RedisConfig extends CachingConfigurerSupport { @Value("${spring.cache.redis.time-to-live}") private Duration timeToLive = Duration.ZERO; /** * 配置Jackson2JsonRedisSerializer序列化策略 * */ private Jackson2JsonRedisSerializer<Object> serializer() { // 使用Jackson2JsonRedisSerializer來(lái)序列化和反序列化redis的value值 Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); ObjectMapper objectMapper = new ObjectMapper(); // 指定要序列化的域,field,get和set,以及修飾符范圍,ANY是都有包括private和public objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); // 指定序列化輸入的類型,類必須是非final修飾的,final修飾的類,比如String,Integer等會(huì)跑出異常 objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(objectMapper); return jackson2JsonRedisSerializer; } @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); // 用Jackson2JsonRedisSerializer來(lái)序列化和反序列化redis的value值 redisTemplate.setValueSerializer(serializer()); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // 使用StringRedisSerializer來(lái)序列化和反序列化redis的key值 redisTemplate.setKeySerializer(stringRedisSerializer); // hash的key也采用String的序列化方式 redisTemplate.setHashKeySerializer(stringRedisSerializer); // hash的value序列化方式采用jackson redisTemplate.setHashValueSerializer(serializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; } @Bean public CacheManager cacheManager(RedisConnectionFactory factory) { RedisSerializer<String> redisSerializer = new StringRedisSerializer(); // 配置序列化(解決亂碼的問(wèn)題) RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() // 緩存有效期 .entryTtl(timeToLive) // 使用StringRedisSerializer來(lái)序列化和反序列化redis的key值 .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)) // 使用Jackson2JsonRedisSerializer來(lái)序列化和反序列化redis的value值 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer())) // 禁用空值 .disableCachingNullValues(); return RedisCacheManager.builder(factory) .cacheDefaults(config) .build(); } }
以上就是SpringBoot結(jié)合Redis實(shí)現(xiàn)序列化的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Redis序列化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring?Boot中使用Redis實(shí)戰(zhàn)案例
redis作為一個(gè)高性能的內(nèi)存數(shù)據(jù)庫(kù),如果不會(huì)用就太落伍了,之前在 node.js中用過(guò) redis,本篇記錄如何將 redis 集成到 spring boot 中,下面這篇文章主要給大家介紹了關(guān)于Spring?Boot中使用Redis的相關(guān)資料,需要的朋友可以參考下2023-04-04SpringMVC框架post提交數(shù)據(jù)庫(kù)出現(xiàn)亂碼解決方案
這篇文章主要介紹了SpringMVC框架post提交數(shù)據(jù)庫(kù)出現(xiàn)亂碼解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09java省市級(jí)聯(lián)下拉菜單實(shí)例代碼
這篇文章主要為大家詳細(xì)介紹了java省市級(jí)聯(lián)實(shí)例代碼,具有一定的參考價(jià)值,感興趣的朋友可以參考一下2016-05-05java的SimpleDateFormat線程不安全的幾種解決方案
但我們知道SimpleDateFormat是線程不安全的,處理時(shí)要特別小心,要加鎖或者不能定義為static,要在方法內(nèi)new出對(duì)象,再進(jìn)行格式化,本文就介紹了幾種方法,感興趣的可以了解一下2021-08-08基于Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的數(shù)據(jù)同步組件
這篇文章主要為大家詳細(xì)介紹了如何基于Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的數(shù)據(jù)同步組件,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以了解一下2023-06-06IDEA生成patch和使用patch的方法實(shí)現(xiàn)
比如你本地修復(fù)的 bug,需要把增量文件發(fā)給客戶,很多場(chǎng)景下大家都需要手工整理修改的文件,并整理好目錄,這個(gè)很麻煩,那有沒(méi)有簡(jiǎn)單的技巧呢?本文主要介紹了IDEA生成patch和使用patch的方法實(shí)現(xiàn),感興趣的可以了解一下2023-08-08Java二分法查找_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了Java二分法查找的相關(guān)資料,需要的朋友可以參考下2017-04-04Spring中配置和讀取多個(gè)Properties文件的方式方法
本篇文章主要介紹了Spring中配置和讀取多個(gè)Properties文件的方式方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-04-04解決IDEA中maven導(dǎo)入jar包一直報(bào)錯(cuò)問(wèn)題
這篇文章主要介紹了解決IDEA中maven導(dǎo)入jar包一直報(bào)錯(cuò)問(wèn)題,本文通過(guò)實(shí)例圖文的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04