日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Springboot整合Redis(RedisConfig等工具类编写)

發(fā)布時間:2024/1/18 javascript 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Springboot整合Redis(RedisConfig等工具类编写) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

我們使用的是上一期創(chuàng)建的Spring boot項目,沒看過那篇文章的可以去看看Springboot整合數(shù)據(jù)庫 +JpaRepository實現(xiàn)簡單數(shù)據(jù)查詢

目錄

  • Redis介紹
  • 1.添加依賴
  • 2.在`application.yml`配置Redis
  • 3.在項目中直接引入Redis的問題記錄
  • 4.使用注解來實現(xiàn)redis緩存
    • @Cacheable
    • @CacheEvict
    • @CachePut
    • @Caching
  • 5.編寫RedisConfig
    • 定義key的序列化與反序列化
    • 定義value的序列化與反序列化
    • RedisConfig的編寫
  • 后記
    • 若有錯誤,歡迎指正,互相學(xué)習(xí),相互交流

Redis介紹

Redis 是目前業(yè)界使用最廣泛的內(nèi)存數(shù)據(jù)存儲。相比 Memcached,Redis 支持更豐富的數(shù)據(jù)結(jié)構(gòu),例如 hashes, lists, sets 等,同時支持?jǐn)?shù)據(jù)持久化。

本文介紹 Spring boot 集成 Redis 來實現(xiàn)數(shù)據(jù)緩存

1.添加依賴

在pom文件中添加redis常用依賴

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

2.在application.yml配置Redis

redis:#數(shù)據(jù)庫索引database: 0#服務(wù)器地址host: 127.0.0.1#端口號port: 6379#redis密碼(默認(rèn)為空)password:#連接redis超時時間timeout: 3000

3.在項目中直接引入Redis的問題記錄

在application.yml文件中配置了redis相關(guān)配置了之后呢,我們就可以在使用的類上直接引入RedisTemplate,具體怎么引入看下述代碼

@Autowiredprivate RedisTemplate<Object,Object> redisTemplate;

我這里就在Service實現(xiàn)類上引入了RedisTemplate

第一個問題:存進(jìn)value的Object,必須序列化要不然會報錯

序列化的話在User類上實現(xiàn)Serializable接口即可,看下圖

第二個問題:存進(jìn)redis的key也需要序列化增加其可讀性,我們先來看看不序列化的key

上述的代碼執(zhí)行步驟呢就是先去數(shù)據(jù)庫查詢名稱為userInfoKey的key,然后如果查到了直接返回結(jié)果即可,沒查到就去數(shù)據(jù)庫查詢,并把查詢到的結(jié)果放到緩存里,再返回結(jié)果

執(zhí)行完上面的步驟,在redis里的key應(yīng)該是userInfoKey,但是并不是這樣的,我們?nèi)edis里看看


我框出來的這段就是我們存進(jìn)redis的key可以觀察到,它是一個序列化后的字符串,這樣當(dāng)key比較多的時候,是非常不方便我們觀察的,所以我們在往redis里插入數(shù)據(jù)時,就得設(shè)置key的序列化對象為字符串,加上下面這段代碼即可

redisTemplate.setKeySerializer(new StringRedisSerializer());


將redis現(xiàn)在的key刪除,執(zhí)行完上面的代碼,我們再來看看redis中的key是怎么樣的

所以,當(dāng)我們設(shè)置了key的序列化屬性后,存進(jìn)redis里的就是我們設(shè)置的key,在數(shù)據(jù)庫中也更方便我們的觀察

第三個問題:所生成的key必須是不同的查詢返回的結(jié)果所對應(yīng)的key必須是不同的,如果像我們上面那樣寫出來的代碼,無論我查詢name = "張三"還是name = "李四"返回的結(jié)果是一樣的,因為我們key是寫死的,所以針對不同的查詢,我們必須生成不同的key,例如根據(jù)類名稱、方法名稱、包名稱和方法參數(shù)來生成一個唯一的key,這樣就可以根據(jù)不同的查詢所生成對應(yīng)的key去緩存查詢不同的結(jié)果

上面說了這么多,其實直接使用RedisTemplate還是有很多問題的,一般我們都會使用注解的方式+RedisConfig 來定義貼合我們項目的緩存


4.使用注解來實現(xiàn)redis緩存

針對上面的問題,spring boot引入的redis的包,里面包含了有關(guān)redis的相關(guān)注解,我們來看看

@Cacheable

我給大家解釋一下這個@AliasFor注解,它的意思是別名的意思,看著上面的圖片,也就是key和value互為別名,也就是說@AliasFor必須成對出現(xiàn),且@AliasFor標(biāo)注的字段必須設(shè)置默認(rèn)值,要不然會報錯

@Cacheable可以標(biāo)記在一個方法上,也可以標(biāo)記在一個類上。當(dāng)標(biāo)記在一個方法上時表示該方法是支持緩存的,當(dāng)標(biāo)記在一個類上時則表示該類所有的方法都是支持緩存的

// @Cacheable(value = "'userInfo' + #p0") // @Cacheable(value = "userInfo",key = "#p0")//參數(shù)為user的話key可以使用這個屬性獲取到user內(nèi)的屬性//盡量使用數(shù)據(jù)的唯一變量,不能保證user.name是唯一的 // @Cacheable(value = "userInfo",key = "#user.name") // @Cacheable(value = "userInfo",key = "#p0.name")public User getUserInfo(String name) {return userRepository.findByName(name);}

我們來看看redis中生成的key

就是我們通過了傳進(jìn)來的參數(shù)作為key,保證了每次傳進(jìn)來的參數(shù)不同,查詢緩存返回的結(jié)果不同,這都是Redis內(nèi)部封裝好的key生成策略,我們也可以自定義key的生成策略

我們來重點看看這個condition

@Cacheable(value = "userInfo",key = "#p0",condition = "#p0.equals('張三')")public User getUserInfo(String name) {return userRepository.findByName(name);}

這個字段就是為我們做了一些過濾的操作,也就是說,加上這個字段,就可以寫一些表達(dá)式,向上面這段代碼,當(dāng)我們傳進(jìn)來的參數(shù)為張三時才會進(jìn)行緩存,傳進(jìn)其它的參數(shù)不進(jìn)行緩存,這里可以使用SpringEL表達(dá)式來盡行操作

還有一些其他的屬性,具體我不展開,感興趣的在下面評論我們交流交流

@CacheEvict


這個注解其實就是類似清除緩存的一個觸發(fā)器,當(dāng)它標(biāo)注在類上則說明該類的方法只要執(zhí)行,都會觸發(fā)清除緩存的操作,可以指定清除緩存的key(value)以及使用condition來匹配清除什么樣的key

這里說一下allEntries和beforeInvocation

allEntries表示是否需要清除緩存中的所有元素,屬性為boolean,若為true則無視key(value)所設(shè)置的值,表示清除所有的元素,默認(rèn)為false

beforeInvocation表示是在方法執(zhí)行之前清除緩存還是執(zhí)行之后清除緩存,若為true則表示方法執(zhí)行前清楚緩存,默認(rèn)為false,即方法執(zhí)行成功后才清除緩存,若方法執(zhí)行中拋出異常沒執(zhí)行完則不會清除緩存

@CachePut


與**@Cacheable**的區(qū)別是

@CachePut不會檢查緩存中的數(shù)據(jù),而是每次都會把方法執(zhí)行完,把返回的結(jié)果存到指定緩存中

@Cacheable會去緩存查,如果緩存有,直接從緩存中取出來返回

@Caching


這個注解是可以同時設(shè)置多組**@Cacheable、@CachePut和@CacheEvict**


5.編寫RedisConfig

首先我們要明白RedisConfig中需要包含什么,首先看看我們直接使用RedisTemplate的問題,我們就知道RedisConfig要包含什么了,我們在RedisConfig需要規(guī)定好根據(jù)不同的查詢生成的key,key和value的序列化和反序列化

我們在RedisConfig中配置的自定義方法,最終通過注解引用的就是我們自定義的方法

定義key的序列化與反序列化

因為key在redis通常都是String類型的,我們定義一個將key序列化成String的一個類

實現(xiàn)其RedisSerializer<Object>接口,主要重寫的方法是序列化的過程,因為key不一定是String類型的,還有可能是json類型,如果key為json我們先將key,轉(zhuǎn)化為String類型,再序列化,防止序列化出現(xiàn)問題

public class StringRedisSerializer implements RedisSerializer<Object> {private final Charset charset;private final String target = "\"";private final String replacement = "";public StringRedisSerializer() {this(Charset.forName("UTF8"));}public StringRedisSerializer(Charset charset) {Assert.notNull(charset, "Charset must not be null!");this.charset = charset;}@Overridepublic String deserialize(byte[] bytes) {return (bytes == null ? null : new String(bytes, charset));}//@Overridepublic byte[] serialize(Object object) {String string = JSON.toJSONString(object);if (string == null) {return null;}string = string.replace(target, replacement);return string.getBytes(charset);} }

定義value的序列化與反序列化

與原Redis默認(rèn)的value序列化方法不同的是,我們選擇的是FastJson來value進(jìn)行序列化,而默認(rèn)采用Jackson2Json來盡行序列化

默認(rèn)

重寫方法:

public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");private Class<T> clazz;public FastJsonRedisSerializer(Class<T> clazz) {super();this.clazz = clazz;}@Overridepublic byte[] serialize(T t) throws SerializationException {if (t == null) {return new byte[0];}return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);}@Overridepublic T deserialize(byte[] bytes) throws SerializationException {if (bytes == null || bytes.length <= 0) {return null;}String str = new String(bytes, DEFAULT_CHARSET);return (T) JSON.parseObject(str, clazz);}}

PS:關(guān)于FastJson有很多爭議,具體感興趣的朋友可以去查查看,生產(chǎn)環(huán)境下不推薦使用fastjson,自定義JacksonJson也可以


RedisConfig的編寫

最后的RedisConfig.class,繼承了CachingConfigurerSupport類,重寫了KeyGenerator方法,也就是key的生成策略

@Configuration @ConditionalOnClass(RedisOperations.class) @EnableConfigurationProperties(RedisProperties.class) public class RedisConfig extends CachingConfigurerSupport {/*** 設(shè)置 redis 數(shù)據(jù)默認(rèn)過期時間,默認(rèn)1天* 設(shè)置@cacheable 序列化方式* @return*/@Beanpublic RedisCacheConfiguration redisCacheConfiguration(){FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();//設(shè)置key的時效性,一般為一天就過期configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer)).entryTtl(Duration.ofDays(1));//最后返回我們的配置類return configuration;}//忽略所有類型的警告@SuppressWarnings("all")//spring管理的一個bean,使用@Autowired注入到使用的類即可@Bean(name = "redisTemplate")//注冊相同類型的bean,就不會成功,保持當(dāng)前只有一個名為"redisTemplate"的bean@ConditionalOnMissingBean(name = "redisTemplate")public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<Object, Object> template = new RedisTemplate<>();//序列化FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);// value值的序列化采用fastJsonRedisSerializer,也就是上面我們編寫的fastJsonRedisSerializertemplate.setValueSerializer(fastJsonRedisSerializer);template.setHashValueSerializer(fastJsonRedisSerializer);// 全局開啟AutoType,不建議使用//ParserConfig.getGlobalInstance().setAutoTypeSupport(true);// 建議使用這種方式,小范圍指定白名單ParserConfig.getGlobalInstance().addAccept("com.hecl.zhenghe.domain");// key的序列化采用StringRedisSerializer,也就是我們剛剛編寫的StringRedisSerializertemplate.setKeySerializer(new StringRedisSerializer());template.setHashKeySerializer(new StringRedisSerializer());template.setConnectionFactory(redisConnectionFactory);return template;}/*** 自定義緩存key生成策略* 使用方法 @Cacheable(keyGenerator="keyGenerator")* @return*/@Bean@Override @Bean@Overridepublic KeyGenerator keyGenerator() {return (target, method, params) -> {StringBuilder stringBuilder = new StringBuilder();//加入類名stringBuilder.append(target.getClass().getName());//加入方法名stringBuilder.append(method.getName());//加入包名stringBuilder.append(target.getClass().getPackage());//加入查詢參數(shù)for (Object obj : params) {stringBuilder.append(JSON.toJSONString(obj).hashCode());}//最終我們生成的key就是這四種的結(jié)合,這就能保證我們生成key的唯一性return stringBuilder.toString();};} }

key的過期時間通過Duration設(shè)置還可以設(shè)置多少小時、分鐘過期,下圖為該類的部分方法

當(dāng)我們重寫完上邊的方法之后,redis就會從默認(rèn)使用的序列化反序列化、key的生成策略等都會使用我們自定義的方式了,當(dāng)然還可以重寫當(dāng)緩存報錯時的處理方式,重寫下列紅框的方法即可


其實編寫RedisConfig方法就是對一些現(xiàn)有的Redis方法進(jìn)行重寫 ,讓Redis使用我們重寫的方法,使其更貼合我們的項目,特別是一些高并發(fā)的項目更要注重這些細(xì)節(jié)

轉(zhuǎn)載請標(biāo)注原作者,謝謝你們的支持,能給個小心心嗎?

完成:2021/4/08 22:38 ALiangXLogic

后記

若有錯誤,歡迎指正,互相學(xué)習(xí),相互交流

總結(jié)

以上是生活随笔為你收集整理的Springboot整合Redis(RedisConfig等工具类编写)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。