您好,登錄后才能下訂單哦!
實際 開發(fā) 中 緩存 處理是必須的,不可能我們每次客戶端去請求一次 服務(wù)器 ,服務(wù)器每次都要去 數(shù)據(jù)庫 中進行查找,為什么要使用緩存?說到底是為了提高系統(tǒng)的運行速度。將用戶頻繁訪問的內(nèi)容存放在離用戶最近,訪問速度最 快的 地方,提高用戶的響 應(yīng)速度,今天先來講下在 springboot 中整合 redis 的詳細步驟。
Spring對Redis的支持是使用Spring Data Redis來實現(xiàn)的,一般使用Jedis或者lettuce(默認),Java客戶端在 org.springframework.boot.autoconfigure.data.redis(Spring Boot 2.x) 中redis的自動配置 AutoConfigureDataRedis
RedisAutoConfiguration提供了RedisTemplate與StringRedisTemplate(只針對鍵值都是字符型的數(shù)據(jù))模板,其中注解 @ConditionalOnMissingBean 是關(guān)鍵,表明該Bean如果在Spring中已經(jīng)存在,則忽略,如果沒有存在則在此處注冊由Spring管理,也就是說我們可以“重寫”該bean,實現(xiàn)自己的RedisTemplate與StringRedisTemplate,事實上,是要需要重寫的,理由如下:
@Bean @ConditionalOnMissingBean( name = {"redisTemplate"} ) public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate<Object, Object> template = new RedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } @Bean @ConditionalOnMissingBean public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; }
1)需要spring-boot-starter-cache依賴,管理緩存
<!-- Spring Boot Cache --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>
2)需要spring-boot-starter-data-redis依賴(注:spring boot 2.x改為在data下),支持redis:主要以為Jedis客戶端為主,排除默認的lettuce作為客戶端的依賴
<!-- Redis Cache --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <!-- 排除lettuce包,使用jedis代替--> <exclusions> <exclusion> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> </exclusion> </exclusions> </dependency>
3)需要jedis-client依賴(注:Redis Client 3版本以上會報錯與spring-boot-starter-data-redis沖突,最好使用2.9.x),使用jedis作為客戶端
<!-- Redis Client 3版本以上會報錯與spring-boot-starter-data-redis沖突 --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>
創(chuàng)建RedisConfig配置類,增加@Configuration注解,同時開啟緩存管理支持(添加注解@EnableCaching),繼承CachingConfigurerSupport重寫key生成策略
@Configuration @EnableCaching public class RedisConfig extends CachingConfigurerSupport { /** * 生成key的策略:根據(jù)類名+方法名+所有參數(shù)的值生成唯一的一個key * @return */ @Bean @Override public KeyGenerator keyGenerator() { return (Object target, Method method, Object... params) -> { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); }; } }
之后使用的application.yml配置文件,其中這里已經(jīng)選擇jedis作為客戶端。
# redis 配置 redis: port: 6379 # Redis服務(wù)器連接密碼(默認為空) password: host: xxx.xxx.xxx.xxx database: 0 jedis: pool: #連接池最大連接數(shù)(使用負值表示沒有限制) max-active: 300 # 連接池中的最小空閑連接 max-idle: 100 # 連接池最大阻塞等待時間(使用負值表示沒有限制) max-wait: 10000 # 連接超時時間(毫秒) timeout: 5000
同時讀取配置屬性,注入JedisPoolConfig
/** * redis配置屬性讀取 */ @Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") private int port; @Value("${spring.redis.database}") private int database; @Value("${spring.redis.jedis.pool.max-idle}") private int maxIdle; @Value("${spring.redis.jedis.pool.max-wait}") private long maxWaitMillis; @Value("${spring.redis.jedis.pool.max-active}") private int maxActive; /** * JedisPoolConfig配置 * @return */ @Bean public JedisPoolConfig jedisPoolConfig() { log.info("初始化JedisPoolConfig"); JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxTotal(maxActive); jedisPoolConfig.setMaxWaitMillis(maxWaitMillis); jedisPoolConfig.setMaxIdle(maxIdle); return jedisPoolConfig; }
針對RedisTemplate或StringRedisTemplate進行序列化,同時重寫注冊Bean
RedisTemplate默認使用JdkSerializationRedisSerializer,StringRedisTmeplate默認使用的是StringRedisSerializer。但都是不符合實際要求的
/** * 重新實現(xiàn)RedisTemplate:解決序列化問題 * @param redisConnectionFactory * @return */ @Bean @SuppressWarnings({"rawtype", "unchecked"}) public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){ RedisTemplate<String, Object> template = new RedisTemplate(); template.setConnectionFactory(redisConnectionFactory); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); // 設(shè)置任何字段可見 om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // 設(shè)置不是final的屬性可以轉(zhuǎn)換 om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); log.info("objectMapper: {}", om); jackson2JsonRedisSerializer.setObjectMapper(om); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // key采用String的序列化方式 template.setKeySerializer(stringRedisSerializer); // hash的key采用String的序列化方式 template.setHashKeySerializer(stringRedisSerializer); // value序列化方式采用jackson序列化方式 template.setValueSerializer(jackson2JsonRedisSerializer); // hash的value序列化方式采用jackson序列化方式 template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); template.setEnableTransactionSupport(true); return template; } /** * 重新實現(xiàn)StringRedisTmeplate:鍵值都是String的的數(shù)據(jù) * @param redisConnectionFactory * @return */ @Bean public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { StringRedisTemplate template = new StringRedisTemplate(); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); template.setConnectionFactory(redisConnectionFactory); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // key采用String的序列化方式 template.setKeySerializer(stringRedisSerializer); // hash的key采用String的序列化方式 template.setHashKeySerializer(stringRedisSerializer); // value序列化方式采用jackson序列化方式 template.setValueSerializer(jackson2JsonRedisSerializer); // hash的value序列化方式采用jackson序列化方式 template.setHashValueSerializer(jackson2JsonRedisSerializer); return template; }
注意Spring Boot 1.x與Spring Boot 2.x的區(qū)別,已在代碼中注釋表明,Spring Boot 1.x使用的是JedisConnectionFactory 。而Spring Boot 2.x使用的是RedisStandaloneConfiguration ,之后傳入JedisConnectionFactory返回Bean
/** * 注入RedisConnectionFactory * @return */ @Bean public RedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig) { log.info("初始化JedisConnectionFactory"); /* 在Spring Boot 1.x中已經(jīng)過時,采用RedisStandaloneConfiguration配置 JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig); jedisConnectionFactory.setHostName(host); jedisConnectionFactory.setDatabase(database);*/ // JedisConnectionFactory配置hsot、database、password等參數(shù) RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(); redisStandaloneConfiguration.setHostName(host); redisStandaloneConfiguration.setPort(port); redisStandaloneConfiguration.setDatabase(database); // JedisConnectionFactory配置jedisPoolConfig JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jedisPoolConfigBuilder = (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder(); jedisPoolConfigBuilder.poolConfig(jedisPoolConfig); return new JedisConnectionFactory(redisStandaloneConfiguration); }
/** * * @author jian * @date 2019/4/14 * @description * 1) RedisTemplate(或StringRedisTemplate)雖然已經(jīng)自動配置,但是不靈活(第一沒有序列化,第二泛型為<Object, Object>不是我們想要的類型) * 所以自己實現(xiàn)RedisTemplate或StringRedisTemplate) * 2) 采用RedisCacheManager作為緩存管理器 * */ @Configuration @EnableCaching public class RedisConfig extends CachingConfigurerSupport { private static final Logger log = LoggerFactory.getLogger(RedisConfig.class); /** * redis配置屬性讀取 */ @Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") private int port; @Value("${spring.redis.database}") private int database; @Value("${spring.redis.jedis.pool.max-idle}") private int maxIdle; @Value("${spring.redis.jedis.pool.max-wait}") private long maxWaitMillis; @Value("${spring.redis.jedis.pool.max-active}") private int maxActive; /** * JedisPoolConfig配置 * @return */ @Bean public JedisPoolConfig jedisPoolConfig() { log.info("初始化JedisPoolConfig"); JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxTotal(maxActive); jedisPoolConfig.setMaxWaitMillis(maxWaitMillis); jedisPoolConfig.setMaxIdle(maxIdle); return jedisPoolConfig; } /** * 注入RedisConnectionFactory * @return */ @Bean public RedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig) { log.info("初始化JedisConnectionFactory"); /* 在Spring Boot 1.x中已經(jīng)過時,采用RedisStandaloneConfiguration配置 JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig); jedisConnectionFactory.setHostName(host); jedisConnectionFactory.setDatabase(database);*/ // JedisConnectionFactory配置hsot、database、password等參數(shù) RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(); redisStandaloneConfiguration.setHostName(host); redisStandaloneConfiguration.setPort(port); redisStandaloneConfiguration.setDatabase(database); // JedisConnectionFactory配置jedisPoolConfig JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jedisPoolConfigBuilder = (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder(); jedisPoolConfigBuilder.poolConfig(jedisPoolConfig); return new JedisConnectionFactory(redisStandaloneConfiguration); } /** * 采用RedisCacheManager作為緩存管理器 * @param connectionFactory */ @Bean public CacheManager cacheManager(RedisConnectionFactory connectionFactory) { RedisCacheManager redisCacheManager = RedisCacheManager.create(connectionFactory); return redisCacheManager; } /** * 生成key的策略:根據(jù)類名+方法名+所有參數(shù)的值生成唯一的一個key * @return */ @Bean @Override public KeyGenerator keyGenerator() { return (Object target, Method method, Object... params) -> { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); }; } /** * 重新實現(xiàn)RedisTemplate:解決序列化問題 * @param redisConnectionFactory * @return */ @Bean @SuppressWarnings({"rawtype", "unchecked"}) public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){ RedisTemplate<String, Object> template = new RedisTemplate(); template.setConnectionFactory(redisConnectionFactory); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); // 設(shè)置任何字段可見 om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // 設(shè)置不是final的屬性可以轉(zhuǎn)換 om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); log.info("objectMapper: {}", om); jackson2JsonRedisSerializer.setObjectMapper(om); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // key采用String的序列化方式 template.setKeySerializer(stringRedisSerializer); // hash的key采用String的序列化方式 template.setHashKeySerializer(stringRedisSerializer); // value序列化方式采用jackson序列化方式 template.setValueSerializer(jackson2JsonRedisSerializer); // hash的value序列化方式采用jackson序列化方式 template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); template.setEnableTransactionSupport(true); return template; } /** * 重新實現(xiàn)StringRedisTmeplate:鍵值都是String的的數(shù)據(jù) * @param redisConnectionFactory * @return */ @Bean public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { StringRedisTemplate template = new StringRedisTemplate(); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); template.setConnectionFactory(redisConnectionFactory); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // key采用String的序列化方式 template.setKeySerializer(stringRedisSerializer); // hash的key采用String的序列化方式 template.setHashKeySerializer(stringRedisSerializer); // value序列化方式采用jackson序列化方式 template.setValueSerializer(jackson2JsonRedisSerializer); // hash的value序列化方式采用jackson序列化方式 template.setHashValueSerializer(jackson2JsonRedisSerializer); return template; } }
雖然RedisTemplate與StringRedisTemplate模板有提供的主要數(shù)據(jù)訪問方法:
但是相關(guān)比較抽象,實現(xiàn)起來比較復雜,有必要進一步封裝,比如使用redisTmeplate中的簡單value的get操作:
Object result = null; ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); result = operations.get(key);
但是封裝之后,相對客戶端用戶來說比較明了
/** * 讀取緩存 * * @param key * @return */ public Object get(final String key) { Object result = null; ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); result = operations.get(key); return result; }
完整的簡單工具類如下:
@Component public class RedisUtils { @Autowired private RedisTemplate redisTemplate; /** * 批量刪除對應(yīng)的value * * @param keys */ public void remove(final String... keys) { for (String key : keys) { remove(key); } } /** * 批量刪除key * * @param pattern */ public void removePattern(final String pattern) { Set<Serializable> keys = redisTemplate.keys(pattern); if (keys.size() > 0) { redisTemplate.delete(keys); } } /** * 刪除對應(yīng)的value * * @param key */ public void remove(final String key) { if (exists(key)) { redisTemplate.delete(key); } } /** * 判斷緩存中是否有對應(yīng)的value * * @param key * @return */ public boolean exists(final String key) { return redisTemplate.hasKey(key); } /** * 讀取緩存 * * @param key * @return */ public Object get(final String key) { Object result = null; ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); result = operations.get(key); return result; } /** * 寫入緩存 * * @param key * @param value * @return */ public boolean set(final String key, Object value) { boolean result = false; try { ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); operations.set(key, value); result = true; } catch (Exception e) { e.printStackTrace(); } return result; } /** * 寫入緩存 * * @param key * @param value * @return */ public boolean set(final String key, Object value, Long expireTime) { boolean result = false; try { ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); operations.set(key, value); redisTemplate.expire(key, expireTime, TimeUnit.SECONDS); result = true; } catch (Exception e) { e.printStackTrace(); } return result; } }
需要注意的是一定要實現(xiàn)序列化,并且有序列化版本ID
public class Person implements Serializable { private final long serialVersionUID = 1L; private String id; private String name; private int age; private String gender; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } @Override public String toString() { return "Person{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", age=" + age + ", gender='" + gender + '\'' + '}'; } }
Redis工具類Spring已經(jīng)做了管理(增加@Compent注解),使用很簡單,只需要注入RedisUtils即可
@RunWith(SpringRunner.class) @SpringBootTest public class RedisTest { @Autowired private RedisUtils redisUtils; @Test public void test(){ Person person = new Person(); person.setAge(23); person.setId("001"); person.setName("Zhangsan"); redisUtils.set("person-001", person); System.out.println(redisUtils.get("person-001")); } }
在IDE控制臺中:
在登錄客戶端后查看value值
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對億速云的支持。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。