Spring整合Redis做缓存
YeBin 2017-12-25 tag1
#
# 一、准备相关Jar包
我这里使用的是Spring-data-redis 2.x,如果你使用的是1.x版本的话,配置会有点不同
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 二、Redis相关配置
使用XML方式配置
<context:property-placeholder location="classpath:redis.properties" ignore-unresolvable="true"/>
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="${redis.maxTotal}"/>
<property name="maxIdle" value="${redis.maxIdle}"/>
<property name="maxWaitMillis" value="${redis.maxWaitMillis}"/>
</bean>
<!--Spring-data-redis 2.0以上配置-->
<bean id="redisPassword" class="org.springframework.data.redis.connection.RedisPassword">
<constructor-arg index="0" value="${redis.password}"></constructor-arg>
</bean>
<!--Spring-data-redis 2.0以上配置-->
<bean id="redisStandaloneConfiguration" class="org.springframework.data.redis.connection.RedisStandaloneConfiguration">
<property name="hostName" value="${redis.host}"/>
<property name="port" value="${redis.port}"/>
<property name="password" ref="redisPassword" />
<property name="database" value="${redis.index}"/>
</bean>
<!--Spring-data-redis 2.0以上配置-->
<bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<constructor-arg name="standaloneConfig" ref="redisStandaloneConfiguration"/>
</bean>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 三、配置redisTemplate和序列化器
Spring向我们提供了一个Cache接口,和CacheManager接口,我们要使用Spring-Cache只要实现这两个接口即可,但 redis给我们提供了一个实现
org.springframework.data.redis.cache.RedisCache以及org.springframework.data.redis.cache.RedisCacheManager
1
如果像自己实现就去实现Cache接口,以及CacheManager接口,前者是用来做缓存逻辑,后者是来管理缓存,不过我这里就使用Redis提供的
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="connectionFactory"></property>
<!-- 对于中文的存储 需要进行序列化操作存储 序列化器 -->
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer">
</bean>
</property>
<property name="valueSerializer">
<bean id="jsonRedisSerializer" class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer">
<!-- 使用默认的 ObjectMapper,移除JSON格式化后的 “@Class”节点 -->
<constructor-arg name="mapper">
<bean class="com.fasterxml.jackson.databind.ObjectMapper"/>
</constructor-arg>
</bean>
</property>
</bean>
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager" >
<constructor-arg index="0" >
<bean class="org.springframework.data.redis.cache.DefaultRedisCacheWriter">
<constructor-arg ref="connectionFactory"/>
</bean>
</constructor-arg>
<constructor-arg index="1">
<bean class="org.springframework.data.redis.cache.RedisCacheConfiguration" factory-method="defaultCacheConfig" >
</bean>
</constructor-arg>
</bean>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 四、开启缓存注解
<!--开启缓存注解 Spring的缓存注解-->
<cache:annotation-driven />
1
2
3
2
3
然后再要做缓存的Service上贴上缓存注解 就大功告成了
@Cacheable(cacheNames = "phone:listAll",key = "'phone:'+#start")
public PageInfo<Phone> listAll(Integer start ,Integer pageSize) {
PageHelper.startPage(start,pageSize);
List<Phone> phones = phoneMapper.listAll();
PageInfo<Phone> pageInfo = new PageInfo<>(phones);
return pageInfo;
}
1
2
3
4
5
6
7
2
3
4
5
6
7

缓存的数据就保存到Redis中了,再次查询的时候就直接从redis中拿出来。
# 五、总结
上面可以看出随便把缓存的数据存入了redis中,但并不是我们预期的结果,因为我再前面设置的是Json格式的序列化器,这里用的却是默认的JDK的序列化器,我找了很多资料,自己也折腾了半天,后来才找打问题的所在
@Bean
public RedisCacheManager redisCacheManager(RedisConnectionFactory factory)
{
RedisCacheWriter redisCacheWriter=RedisCacheWriter.lockingRedisCacheWriter(factory);
/* 使用 json 序列化 */
//不做这个配置Json序列化器将不能生效
RedisSerializer<Object> jsonSerializer = new GenericJackson2JsonRedisSerializer();
RedisSerializationContext.SerializationPair<Object> serializationPair = RedisSerializationContext.SerializationPair.fromSerializer(jsonSerializer);
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(serializationPair);
/* 设置保存时间*/
defaultCacheConfig.entryTtl(Duration.ofHours(8));
return new RedisCacheManager(redisCacheWriter, defaultCacheConfig);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
我使用Java Congfig的方式注入了一个CacheManager,再此尝试后:

数据以json各是保存起来了,我分析了很久,对比XML和JavaConfig的方式,找出了原因:我再使用XML方式配置CacheManager的时候,没有没有给它设置serializerPair,这才导致之前设置的json序列化器没生效:
public RedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
this(cacheWriter, defaultCacheConfiguration, true);
}
redisCacheManager需要有连个参数的构造函数,cacheWriter和RedisCacheConfigruation
而RedisCacheConfigruation 需要给它设置一个alueSerializationPair,否者就会使用默认的jdk序列化器
public RedisCacheConfiguration serializeValuesWith(SerializationPair<?> valueSerializationPair) {
Assert.notNull(valueSerializationPair, "ValueSerializationPair must not be null!");
return new RedisCacheConfiguration(this.ttl, this.cacheNullValues, this.usePrefix, this.keyPrefix, this.keySerializationPair, valueSerializationPair, this.conversionService);
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10