SpringBoot使用注解集成Redis緩存的示例代碼
Spring Boot 熟悉后,集成一個(gè)外部擴(kuò)展是一件很容易的事,集成Redis也很簡(jiǎn)單,看下面步驟配置:
一、添加pom依賴(lài)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> </dependency>
二、創(chuàng)建 RedisClient.java 注意該類(lèi)存放的package
package org.springframework.data.redis.connection.jedis; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.UnsupportedEncodingException; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import redis.clients.jedis.Jedis; import redis.clients.jedis.Protocol; import redis.clients.jedis.exceptions.JedisException; /** * 工具類(lèi) RedisClient * 因?yàn)楸绢?lèi)中獲取JedisPool調(diào)用的是JedisConnectionFactory中protected修飾的方法fetchJedisConnector() * 所以該類(lèi)需要與JedisConnectionFactory在同一個(gè)package中 * * @author 單紅宇(CSDN CATOOP) * @create 2017年4月9日 */ public class RedisClient { private static Logger logger = LoggerFactory.getLogger(RedisClient.class); private JedisConnectionFactory factory; public RedisClient(JedisConnectionFactory factory) { super(); this.factory = factory; } /** * put操作(存儲(chǔ)序列化對(duì)象)+ 生效時(shí)間 * * @param key * @param value * @return */ public void putObject(final String key, final Object value, final int cacheSeconds) { if (StringUtils.isNotBlank(key)) { redisTemplete(key, new RedisExecute<Object>() { @Override public Object doInvoker(Jedis jedis) { try { jedis.setex(key.getBytes(Protocol.CHARSET), cacheSeconds, serialize(value)); } catch (UnsupportedEncodingException e) { } return null; } }); } } /** * get操作(獲取序列化對(duì)象) * * @param key * @return */ public Object getObject(final String key) { return redisTemplete(key, new RedisExecute<Object>() { @Override public Object doInvoker(Jedis jedis) { try { byte[] byteKey = key.getBytes(Protocol.CHARSET); byte[] byteValue = jedis.get(byteKey); if (byteValue != null) { return deserialize(byteValue); } } catch (UnsupportedEncodingException e) { return null; } return null; } }); } /** * setex操作 * * @param key * 鍵 * @param value * 值 * @param cacheSeconds * 超時(shí)時(shí)間,0為不超時(shí) * @return */ public String set(final String key, final String value, final int cacheSeconds) { return redisTemplete(key, new RedisExecute<String>() { @Override public String doInvoker(Jedis jedis) { if (cacheSeconds == 0) { return jedis.set(key, value); } return jedis.setex(key, cacheSeconds, value); } }); } /** * get操作 * * @param key * 鍵 * @return 值 */ public String get(final String key) { return redisTemplete(key, new RedisExecute<String>() { @Override public String doInvoker(Jedis jedis) { String value = jedis.get(key); return StringUtils.isNotBlank(value) && !"nil".equalsIgnoreCase(value) ? value : null; } }); } /** * del操作 * * @param key * 鍵 * @return */ public long del(final String key) { return redisTemplete(key, new RedisExecute<Long>() { @Override public Long doInvoker(Jedis jedis) { return jedis.del(key); } }); } /** * 獲取資源 * * @return * @throws JedisException */ public Jedis getResource() throws JedisException { Jedis jedis = null; try { jedis = factory.fetchJedisConnector(); } catch (JedisException e) { logger.error("getResource.", e); returnBrokenResource(jedis); throw e; } return jedis; } /** * 獲取資源 * * @return * @throws JedisException */ public Jedis getJedis() throws JedisException { return getResource(); } /** * 歸還資源 * * @param jedis * @param isBroken */ public void returnBrokenResource(Jedis jedis) { if (jedis != null) { jedis.close(); } } /** * 釋放資源 * * @param jedis * @param isBroken */ public void returnResource(Jedis jedis) { if (jedis != null) { jedis.close(); } } /** * 操作jedis客戶(hù)端模板 * * @param key * @param execute * @return */ public <R> R redisTemplete(String key, RedisExecute<R> execute) { Jedis jedis = null; try { jedis = getResource(); if (jedis == null) { return null; } return execute.doInvoker(jedis); } catch (Exception e) { logger.error("operator redis api fail,{}", key, e); } finally { returnResource(jedis); } return null; } /** * 功能簡(jiǎn)述: 對(duì)實(shí)體Bean進(jìn)行序列化操作. * * @param source * 待轉(zhuǎn)換的實(shí)體 * @return 轉(zhuǎn)換之后的字節(jié)數(shù)組 * @throws Exception */ public static byte[] serialize(Object source) { ByteArrayOutputStream byteOut = null; ObjectOutputStream ObjOut = null; try { byteOut = new ByteArrayOutputStream(); ObjOut = new ObjectOutputStream(byteOut); ObjOut.writeObject(source); ObjOut.flush(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (null != ObjOut) { ObjOut.close(); } } catch (IOException e) { ObjOut = null; } } return byteOut.toByteArray(); } /** * 功能簡(jiǎn)述: 將字節(jié)數(shù)組反序列化為實(shí)體Bean. * * @param source * 需要進(jìn)行反序列化的字節(jié)數(shù)組 * @return 反序列化后的實(shí)體Bean * @throws Exception */ public static Object deserialize(byte[] source) { ObjectInputStream ObjIn = null; Object retVal = null; try { ByteArrayInputStream byteIn = new ByteArrayInputStream(source); ObjIn = new ObjectInputStream(byteIn); retVal = ObjIn.readObject(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (null != ObjIn) { ObjIn.close(); } } catch (IOException e) { ObjIn = null; } } return retVal; } interface RedisExecute<T> { T doInvoker(Jedis jedis); } }
三、創(chuàng)建Redis配置類(lèi)
RedisConfig.java
package com.shanhy.example.redis; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.connection.jedis.RedisClient; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.StringRedisSerializer; /** * Redis配置 * * @author 單紅宇(CSDN catoop) * @create 2016年9月12日 */ @Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(JedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<String, Object>(); template.setConnectionFactory(factory); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new RedisObjectSerializer()); template.afterPropertiesSet(); return template; } @Bean public RedisClient redisClient(JedisConnectionFactory factory){ return new RedisClient(factory); } } RedisObjectSerializer.java package com.shanhy.example.redis; import org.springframework.core.convert.converter.Converter; import org.springframework.core.serializer.support.DeserializingConverter; import org.springframework.core.serializer.support.SerializingConverter; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.SerializationException; /** * 實(shí)現(xiàn)對(duì)象的序列化接口 * @author 單紅宇(365384722) * @myblog http://blog.csdn.net/catoop/ * @create 2017年4月9日 */ public class RedisObjectSerializer implements RedisSerializer<Object> { private Converter<Object, byte[]> serializer = new SerializingConverter(); private Converter<byte[], Object> deserializer = new DeserializingConverter(); static final byte[] EMPTY_ARRAY = new byte[0]; @Override public Object deserialize(byte[] bytes) { if (isEmpty(bytes)) { return null; } try { return deserializer.convert(bytes); } catch (Exception ex) { throw new SerializationException("Cannot deserialize", ex); } } @Override public byte[] serialize(Object object) { if (object == null) { return EMPTY_ARRAY; } try { return serializer.convert(object); } catch (Exception ex) { return EMPTY_ARRAY; } } private boolean isEmpty(byte[] data) { return (data == null || data.length == 0); } }
四、創(chuàng)建測(cè)試方法 下面代碼隨便放一個(gè)Controller里
@Autowired private RedisTemplate<String, Object> redisTemplate; /** * 緩存測(cè)試 * * @return * @author SHANHY * @create 2016年9月12日 */ @RequestMapping("/redisTest") public String redisTest() { try { redisTemplate.opsForValue().set("test-key", "redis測(cè)試內(nèi)容", 2, TimeUnit.SECONDS);// 緩存有效期2秒 logger.info("從Redis中讀取數(shù)據(jù):" + redisTemplate.opsForValue().get("test-key").toString()); TimeUnit.SECONDS.sleep(3); logger.info("等待3秒后嘗試讀取過(guò)期的數(shù)據(jù):" + redisTemplate.opsForValue().get("test-key")); } catch (InterruptedException e) { e.printStackTrace(); } return "OK"; }
五、配置文件配置Redis application.yml
spring: # Redis配置 redis: host: 192.168.1.101 port: 6379 password: # 連接超時(shí)時(shí)間(毫秒) timeout: 10000 pool: max-idle: 20 min-idle: 5 max-active: 20 max-wait: 2
這樣就完成了Redis的配置,可以正常使用 redisTemplate 了。
一、創(chuàng)建 Caching 配置類(lèi)
RedisKeys.java
package com.shanhy.example.redis; import java.util.HashMap; import java.util.Map; import javax.annotation.PostConstruct; import org.springframework.stereotype.Component; /** * 方法緩存key常量 * * @author SHANHY */ @Component public class RedisKeys { // 測(cè)試 begin public static final String _CACHE_TEST = "_cache_test";// 緩存key public static final Long _CACHE_TEST_SECOND = 20L;// 緩存時(shí)間 // 測(cè)試 end // 根據(jù)key設(shè)定具體的緩存時(shí)間 private Map<String, Long> expiresMap = null; @PostConstruct public void init(){ expiresMap = new HashMap<>(); expiresMap.put(_CACHE_TEST, _CACHE_TEST_SECOND); } public Map<String, Long> getExpiresMap(){ return this.expiresMap; } }
CachingConfig.java
package com.shanhy.example.redis; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.cache.interceptor.SimpleKeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.core.RedisTemplate; /** * 注解式環(huán)境管理 * * @author 單紅宇(CSDN catoop) * @create 2016年9月12日 */ @Configuration @EnableCaching public class CachingConfig extends CachingConfigurerSupport { /** * 在使用@Cacheable時(shí),如果不指定key,則使用找個(gè)默認(rèn)的key生成器生成的key * * @return * * @author 單紅宇(CSDN CATOOP) * @create 2017年3月11日 */ @Override public KeyGenerator keyGenerator() { return new SimpleKeyGenerator() { /** * 對(duì)參數(shù)進(jìn)行拼接后MD5 */ @Override public Object generate(Object target, Method method, Object... params) { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append(".").append(method.getName()); StringBuilder paramsSb = new StringBuilder(); for (Object param : params) { // 如果不指定,默認(rèn)生成包含到鍵值中 if (param != null) { paramsSb.append(param.toString()); } } if (paramsSb.length() > 0) { sb.append("_").append(paramsSb); } return sb.toString(); } }; } /** * 管理緩存 * * @param redisTemplate * @return */ @Bean public CacheManager cacheManager(RedisTemplate<String, Object> redisTemplate, RedisKeys redisKeys) { RedisCacheManager rcm = new RedisCacheManager(redisTemplate); // 設(shè)置緩存默認(rèn)過(guò)期時(shí)間(全局的) rcm.setDefaultExpiration(1800);// 30分鐘 // 根據(jù)key設(shè)定具體的緩存時(shí)間,key統(tǒng)一放在常量類(lèi)RedisKeys中 rcm.setExpires(redisKeys.getExpiresMap()); List<String> cacheNames = new ArrayList<String>(redisKeys.getExpiresMap().keySet()); rcm.setCacheNames(cacheNames); return rcm; } }
二、創(chuàng)建需要緩存數(shù)據(jù)的類(lèi)
TestService.java
package com.shanhy.example.service; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import com.shanhy.example.redis.RedisKeys; @Service public class TestService { /** * 固定key * * @return * @author SHANHY * @create 2017年4月9日 */ @Cacheable(value = RedisKeys._CACHE_TEST, key = "'" + RedisKeys._CACHE_TEST + "'") public String testCache() { return RandomStringUtils.randomNumeric(4); } /** * 存儲(chǔ)在Redis中的key自動(dòng)生成,生成規(guī)則詳見(jiàn)CachingConfig.keyGenerator()方法 * * @param str1 * @param str2 * @return * @author SHANHY * @create 2017年4月9日 */ @Cacheable(value = RedisKeys._CACHE_TEST) public String testCache2(String str1, String str2) { return RandomStringUtils.randomNumeric(4); } }
說(shuō)明一下,其中 @Cacheable 中的 value 值是在 CachingConfig的cacheManager 中配置的,那里是為了配置我們的緩存有效時(shí)間。其中 methodKeyGenerator 為 CachingConfig 中聲明的 KeyGenerator。 另外,Cache 相關(guān)的注解還有幾個(gè),大家可以了解下,不過(guò)我們常用的就是 @Cacheable,一般情況也可以滿(mǎn)足我們的大部分需求了。還有 @Cacheable 也可以配置表達(dá)式根據(jù)我們傳遞的參數(shù)值判斷是否需要緩存。 注: TestService 中 testCache 中的 mapper.get 大家不用關(guān)心,這里面我只是訪問(wèn)了一下數(shù)據(jù)庫(kù)而已,你只需要在這里做自己的業(yè)務(wù)代碼即可。
三、測(cè)試方法
下面代碼,隨便放一個(gè) Controller 中
package com.shanhy.example.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.connection.jedis.RedisClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.shanhy.example.service.TestService; /** * 測(cè)試Controller * * @author 單紅宇(365384722) * @myblog http://blog.csdn.net/catoop/ * @create 2017年4月9日 */ @RestController @RequestMapping("/test") public class TestController { private static final Logger LOG = LoggerFactory.getLogger(TestController.class); @Autowired private RedisClient redisClient; @Autowired private TestService testService; @GetMapping("/redisCache") public String redisCache() { redisClient.set("shanhy", "hello,shanhy", 100); LOG.info("getRedisValue = {}", redisClient.get("shanhy")); testService.testCache2("aaa", "bbb"); return testService.testCache(); } }
至此完畢!
最后說(shuō)一下,這個(gè) @Cacheable 基本是可以放在所有方法上的,Controller 的方法上也是可以的(這個(gè)我沒(méi)有測(cè)試 ^_^)。
以上就是SpringBoot使用注解集成Redis緩存的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot注解集成Redis緩存的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
MyBatis-Plus聯(lián)表查詢(xún)及分頁(yè)代碼舉例
本文介紹了mybatis-plus-join工具的使用,該工具可以簡(jiǎn)化mybatis-plus的聯(lián)表查詢(xún),使得開(kāi)發(fā)者可以以類(lèi)似QueryWrapper的方式進(jìn)行聯(lián)表查詢(xún),無(wú)需手動(dòng)編寫(xiě)xml文件,感興趣的朋友跟隨小編一起看看吧2025-03-03new出來(lái)的對(duì)象中無(wú)法使用@autowired進(jìn)行對(duì)象bean注入問(wèn)題
這篇文章主要介紹了基于new出來(lái)的對(duì)象中無(wú)法使用@autowired進(jìn)行對(duì)象bean注入問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02rocketmq的AclClientRPCHook權(quán)限控制使用技巧示例詳解
這篇文章主要為大家介紹了rocketmq的AclClientRPCHook使用技巧示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08Java工具類(lèi)之@RequestMapping注解
今天帶大家來(lái)學(xué)習(xí)Java工具類(lèi),文中對(duì)注解@RequestMapping作了非常詳細(xì)的介紹,對(duì)正在學(xué)習(xí)java的小伙伴們很有幫助,需要的朋友可以參考下2021-05-05java實(shí)現(xiàn)學(xué)生選課系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)學(xué)生選課系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-02-02Java實(shí)現(xiàn)微信公眾平臺(tái)朋友圈分享功能詳細(xì)代碼
這篇文章主要介紹了Java實(shí)現(xiàn)微信公眾平臺(tái)朋友圈分享功能詳細(xì)代碼,小編覺(jué)得挺不錯(cuò)的,這里分享給大家,供需要的朋友參考。2017-11-11詳解Spring Boot中整合Sharding-JDBC讀寫(xiě)分離示例
這篇文章主要介紹了詳解Spring Boot中整合Sharding-JDBC讀寫(xiě)分離示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-03-03