您的位置:首页 > 数据库 > Redis

SpringBoot中使用Redis实现缓存

2017-04-19 14:09 676 查看
摘要: 原创出处 http://peijie2016.oschina.io 欢迎转载,保留摘要,谢谢!

Spring Data Redis为我们封装了Redis客户端的各种操作,简化使用。

- 当Redis当做数据库或者消息队列来操作时,我们一般使用RedisTemplate来操作

- 当Redis作为缓存使用时,我们可以将它作为Spring Cache的实现,直接通过注解使用

关于RedisTemplate的使用可参考:http://blog.didispace.com/springbootredis/

下面总结使用Redis作为缓存

引入依赖

SpringBoot从1.4版本开始,
spring-boot-starter-redis
依赖改名了。

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


配置文件

spring:
redis:
host: 127.0.0.1
port: 6379
timeout: 0
database: 0
pool:
max-active: 8
max-wait: -1
max-idle: 8
min-idle: 0


这样,SpringBoot将会自动配置redis,注入相关bean,我们就可以使用
@CacheConfig
@Cacheable
@CachePut
@CacheEvict
了。

使用Cache注解时的问题

缓存对象集合中,缓存是以key-value形式保存的。当不指定缓存的key时,SpringBoot会使用
SimpleKeyGenerator
生成key。

public class SimpleKeyGenerator implements KeyGenerator {

@Override
public Object generate(Object target, Method method, Object... params) {
return generateKey(params);
}

/**
* Generate a key based on the specified parameters.
*/
public static Object generateKey(Object... params) {
if (params.length == 0) {
return SimpleKey.EMPTY;
}
if (params.length == 1) {
Object param = params[0];
if (param != null && !param.getClass().isArray()) {
return param;
}
}
return new SimpleKey(params);
}
}


public SimpleKey(Object... elements) {
Assert.notNull(elements, "Elements must not be null");
this.params = new Object[elements.length];
System.arraycopy(elements, 0, this.params, 0, elements.length);
this.hashCode = Arrays.deepHashCode(this.params);
}


查看源码可以发现,它是使用方法参数组合生成的一个key。

此时有一个问题:

如果2个方法,参数是一样的,但执行逻辑不同,那么将会导致执行第二个方法时命中第一个方法的缓存。

解决办法是在
@Cacheable
注解参数中指定key,或者自己实现一个
KeyGenerator
,在注解中指定KeyGenerator。

但是如果这样的情况很多,每一个都要指定key、KeyGenerator很麻烦。

Spring同样提供了方案:继承
CachingConfigurerSupport
并重写
keyGenerator()


下面贴出代码:

@EnableCaching
@Configuration
public class RedisCacheConfig extends CachingConfigurerSupport {

@Autowired
private JedisConnectionFactory jedisConnectionFactory;

@Bean
public RedisTemplate redisTemplate() {
StringRedisTemplate redisTemplate = new StringRedisTemplate(jedisConnectionFactory);

Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);

redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}

@Bean
public CacheManager cacheManager() {
String[] cacheNames = {"app_default", "users", "blogs", "goods", "configs", "info"};
RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate(), Arrays.asList(cacheNames));
redisCacheManager.setDefaultExpiration(86400);
return redisCacheManager;
}

@Bean
public Cache cache() {
return cacheManager().getCache("app_default");
}

@Bean
@Override
public KeyGenerator keyGenerator() {
return (target, method, objects) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append("::" + method.getName() + ":");
for (Object obj : objects) {
sb.append(obj.toString());
}
return sb.toString();
};
}
}


此时,缓存的key是包名+方法名+参数列表,这样就很难会冲突了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  redis spring