您的当前位置:首页正文

Springboot整合redis使用技巧

2024-03-17 来源:汇智旅游网
Springboot整合redis使用技巧

Spring Cache

Spring 3.1 引入基于注解Cache支持,且提供了Cache抽象。

Spring 的缓存技术还具备相当的灵活性,不仅能够使用 SpEL(Spring Expression Language)来定义缓存的 key 和各种 condition,还提供开箱即用的缓存临时存储方案,也支持和主流的专业缓存例如 EHCache、Redis 集成。

Spring提供的核心Cache接口: 1. package org.springframework.cache; 2. 3. public interface Cache { 4. String getName(); //缓存的名字 5. Object getNativeCache(); //底层使用的缓存,如Ehcache、Redis 6. ValueWrapper get(Object key); //根据key得到一个ValueWrapper,然后调用其get方法获取值 7. T get(Object key, Class type);//根据key,和value的类型直接获取value 8. void put(Object key, Object value);//往缓存放数据 9. void evict(Object key);//移除key对应的缓存 10. void clear(); //清空缓存 11. 12. interface ValueWrapper { //缓存值的Wrapper 13. Object get(); //得到真实的value 14. } 15. } spring cache可以满足一般应用对缓存的需求,但是对于一些复杂的应用场景就不能直接使用,比如在Spring提供抽象API中并没有提供缓存策略的解决方案,缓存策略都是由底层Cache自行维护。

在Springboot中提供了基于spring cache的自动化配置,默认提供了Ehcache、Guava、Redis等的配置实现。我们在应用开发中使用的是Redis缓存,并且出现了一些复杂的应用场景,需要对于不同缓存制定不同的策略。

查看了Springboot实现Redis自动化配置的源码。发现在RedisCacheManager类中有这两个属性defaultExpiration和expires。

这时候就可以通过在Spring注册一个RedisCacheManager实现缓存策略(源码)。

配置多个Cache Manager实例与使用

如果想要实现多个Cache Manager实例也是可以的,比如还想要一个内存缓存GuavaCache,需要使用@Primary注解指定一个Cache Manager作为默认缓存。(在创建bean的时候最好指定缓存管理实例的bean名称),使用的时候不指定缓存管理实例名称就使用默认缓存,指定缓存管理实例就是使用指定的缓存管理实例。

例如:

@Cacheable(value = \"cache \//使用redisCacheManager,由@Primary指定 @Cacheable(cacheNames = \"guavaCacheManager\\"key\")//使用guavaCacheManager

Redis缓存使用技巧

在redisCacheManager配置中有一个比较有意思的配置属性:usePrefix;这个表示缓存数据时,缓存的键是否使用前缀。

通过源码可以看到,如果不使用前缀,redis将会在缓存中维护一个有序集合(SortedSet)来保存该类缓存数据的key,方便维护(如清空缓存)。但是需要注意,这个有序集合在缓存的数据量过大的时候,会导致redis访问出现异常甚至宕机。

当使用缓存前缀时,将会使用缓存名称作为前缀,并且默认以冒号分割(cache:key)。 这个中使用方式可以缓存上亿数据,redis也能正常提供服务。这种使用方式禁止使用clear()方法清空缓存(特别是在redis中有大量数据时),这个方法使用的是keys去找对应的key并删除数据,clear()方法调用将导致redis长时间不可用。

建议:使用redis时,要设置过期时间,使用前缀缓存,禁止(keys)清空缓存数据,让缓存自动过期,(如果确实不使用该数据,可以换一个缓存名称)。

内存缓存使用注意

使用内存缓存时,应该作为只读缓存。不要修改数据,特别是一些引用数据,内存缓存对象没有实现序列化,当你修改的时候,会改变原有引用的数据。如果需要修改数据,可以自己实现序列化和反序列化。

源码

配置文件 代码实现: package com.zto.thrall.business.redis; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.data.redis.RedisProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.guava.GuavaCache; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.cache.support.SimpleCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.cache.CacheBuilder; import redis.clients.jedis.JedisPoolConfig; /** * Created by yt on 2017-3-6. */ @Configuration @EnableCaching @EnableConfigurationProperties(RedisProperties.class) @ConfigurationProperties(prefix =\"redis-expires\") public class RedisConfig extends CachingConfigurerSupport { @Autowired private RedisProperties redisProperties; private List cacheNames = new ArrayList(); private long defaultExpiration; private Map expires; public List getCacheNames() { return cacheNames; } public void setCacheNames(List cacheNames) { this.cacheNames = cacheNames; } public long getDefaultExpiration() { return defaultExpiration; } public void setDefaultExpiration(long defaultExpiration) { this.defaultExpiration = defaultExpiration; } public Map getExpires() { return expires; } public void setExpires(Map expires) { this.expires = expires; } @Bean public KeyGenerator keyGenerator(){ //重写缓存key生成机制 return new KeyGenerator() { @Override public Object generate(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(); } }; } @Bean(name = \"redisCacheManager\") @Primary public CacheManager redisCacheManager(RedisTemplate redisTemplate) { RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate); redisCacheManager.setCacheNames(cacheNames); redisCacheManager.setDefaultExpiration(defaultExpiration); redisCacheManager.setExpires(expires); //设置缓存过期时间 redisCacheManager.setUsePrefix(true); //是否使用缓存前缀 redisCacheManager.afterPropertiesSet(); return redisCacheManager; } @Bean(name = \"guavaCacheManager\") public CacheManager guavaCacheManager() { SimpleCacheManager cacheManager = new SimpleCacheManager(); ArrayList caches = new ArrayList(); caches.add(new GuavaCache(\"guavaCache\CacheBuilder.newBuilder().maximumSize(30000).expireAfterWrite(2, TimeUnit.HOURS).build())); cacheManager.setCaches(caches); return cacheManager; } @Bean public RedisTemplate redisTemplate(JedisConnectionFactory jedisConnectionFactory) { RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(jedisConnectionFactory); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(objectMapper); redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); redisTemplate.afterPropertiesSet(); return redisTemplate; } @Bean public JedisConnectionFactory redisConnectionFactory() { JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(); redisConnectionFactory.setHostName(redisProperties.getHost()); redisConnectionFactory.setPort(redisProperties.getPort()); redisConnectionFactory.setPassword(redisProperties.getPassword()); redisConnectionFactory.setTimeout(redisProperties.getTimeout()); redisConnectionFactory.setPoolConfig(jedisPoolConfig()); redisConnectionFactory.afterPropertiesSet(); return redisConnectionFactory; } private JedisPoolConfig jedisPoolConfig() { JedisPoolConfig config = new JedisPoolConfig(); RedisProperties.Pool props = this.redisProperties.getPool(); config.setMaxTotal(props.getMaxActive()); config.setMaxIdle(props.getMaxIdle()); config.setMinIdle(props.getMinIdle()); config.setMaxWaitMillis(props.getMaxWait()); return config; } }

因篇幅问题不能全部显示,请点此查看更多更全内容