在Spring里引用Redis访问组件是有版本要求的, 最好在http://mvnrepository.com里面找清楚,本人因为这个问题浪费了不少时间, 这里的Spring为4.2, spring-data-redis为1.6.0,以下为pom.xml增加内容:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-redis -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.6.0.RELEASE</version>
</dependency>
然后, 在spring配置里面引用以下关于redis的配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-4.0.xsd"
>
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" >
<property name="locations">
<list>
<value>classpath:redis-config.properties</value>
</list>
</property>
<property name="ignoreUnresolvablePlaceholders" value="true" />
</bean>
<!-- 配置JedisPoolConfig实例 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="maxTotal" value="${redis.maxActive}" />
<property name="maxWaitMillis" value="${redis.maxWait}" />
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean>
<!-- 配置JedisConnectionFactory -->
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="${redis.host}" />
<property name="port" value="${redis.port}" />
<property name="password" value="${redis.passwd}" />
<property name="database" value="${redis.dbIndex}" />
<property name="poolConfig" ref="poolConfig" />
</bean>
<!-- 定义序列化转换器 -->
<bean id="commonSerializer" class="org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer">
<constructor-arg type="java.lang.Class" value="java.lang.Object" index="0"/>
</bean>
<bean id="jdkSerializer"
class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
<!-- 配置RedisTemplate -->
<bean id="defaultRedisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory" />
<property name="defaultSerializer" ref="commonSerializer" />
<!--
<property name="keySerializer" ref="Jackson2JsonRedisSerializer" />
<property name="hashKeySerializer" ref="Jackson2JsonRedisSerializer" />
<property name="valueSerializer" ref="Jackson2JsonRedisSerializer" />
<property name="valueSerializer" ref="Jackson2JsonRedisSerializer" />
-->
</bean>
<!-- 配置RedisTemplate -->
<bean id="pageTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory" />
<property name="defaultSerializer" ref="commonSerializer" />
<property name="valueSerializer" ref="pageSerializer" />
</bean>
<!-- spring自己的换管理器,这里定义了两个缓存位置名称 ,既注解中的value -->
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="com.freestyle.common.spring.redis.MyRedisCache">
<constructor-arg name="name" value="default"></constructor-arg>
<constructor-arg name="prefix" value="#{null}"> </constructor-arg>
<constructor-arg name="redisOperations" ref="defaultRedisTemplate"></constructor-arg>
<constructor-arg name="expiration" value="${redis.expiration}"></constructor-arg>
</bean>
<bean class="com.freestyle.common.spring.redis.MyRedisCache">
<constructor-arg name="name" value="pageCache"></constructor-arg>
<constructor-arg name="prefix" value="#{null}"> </constructor-arg>
<constructor-arg name="redisOperations" ref="pageTemplate"></constructor-arg>
<constructor-arg name="expiration" value="${redis.expiration}"></constructor-arg>
</bean>
</set>
</property>
</bean>
<!-- 注入redisCachemanager -->
<cache:annotation-driven cache-manager="cacheManager"/>
<!-- 配置Jedis Pool -->
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg name="poolConfig" ref="poolConfig" >
</constructor-arg>
<constructor-arg name="host" value="${redis.host}" >
</constructor-arg>
<constructor-arg name="port" value="${redis.port}" type="int">
</constructor-arg>
<constructor-arg name="timeout" value="2000" type="int">
</constructor-arg>
<constructor-arg name="password" value="${redis.passwd}">
</constructor-arg>
</bean>
<bean id="jRedisUtils" class="com.freestyle.common.utils.JRedisUtils">
<constructor-arg ref="jedisPool"></constructor-arg>
<property name="databaseIndex" value="${redis.dbIndex}"></property>
</bean>
<!-- redis config end -->
</beans>
需要说明的是由于本人定义的通用分布查询类Page,用默认的Jackson2JsonRedisSerializer无法还原,会发生不能将linkedhashmap转为..Page之类的异常, 所以特地为此写了一个专用 的pageTemplate和一个名为pageCache的Cache。也就是说, cacheManager管理器里面有两组cache,一组名为default,另一组名为pageCache,是专门用于缓冲Page类型的数据。这里说明一下为什么要弄那么麻烦整两组cache出来, 网上配置spring-redis都没有这么复杂, 因为spring-redis集成组件默认是用JdkSerializationRedisSerializer来进行序列化的,而用默认的序列化是没有问题的,而且能处理任何类的转换。但上一篇测试已经证明jdk内置的序列化性能远不及jason json,所以我比较偏向性能优先。
在src/main/resources下建立Redis连接配置文件redis-config.properties,此文件作为参数被spring读入并以${redis.host}这样的表达式给组装bean时引用。
redis.host=127.0.0.1
redis.port=6379
redis.passwd=yourpassword
redis.dbIndex=0
redis.maxIdle=300
redis.maxActive=600
redis.maxWait=1000
redis.testOnBorrow=true
#RedisCacheManager用,到期时间(秒)
redis.expiration=1800
配置器,导出一个:
package com.freestyle.common.spring;
import java.lang.reflect.Method;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableCaching
public class MyCachingConfigurerSupport extends CachingConfigurerSupport {
public MyCachingConfigurerSupport() {
// TODO Auto-generated constructor stub
}
@Bean
public PageJsonRedisSerializer pageSerializer() {
PageJsonRedisSerializer lvRet=new PageJsonRedisSerializer();
return lvRet;
}
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... 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();
}
};
}
}
自定义Page相关的PageJsonRedisSerializer,重写deserialize,原来GenericJackson2JsonRedisSerializer默认是Object类型的,上面提及的异常就是由于这个引起民的, 所以这里显式指定为Page:
package com.freestyle.common.spring;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.freestyle.common.hibernate.dao.support.Page;
public class PageJsonRedisSerializer extends GenericJackson2JsonRedisSerializer {
public PageJsonRedisSerializer() {
// TODO Auto-generated constructor stub
}
public PageJsonRedisSerializer(String classPropertyTypeName) {
super(classPropertyTypeName);
// TODO Auto-generated constructor stub
}
public PageJsonRedisSerializer(ObjectMapper mapper) {
super(mapper);
}
@Override
public Page deserialize(byte[] source) throws SerializationException {
return super.deserialize(source, Page.class);
}
}
调用:
....
@Service
public class QuotedNoteModule extends QuotedNoteModuleP {
@Cacheable(value="pageCache",keyGenerator="keyGenerator")
@Override
public Page getOrderList(CommonReqInqBean pvReq, String pvLogin,Locale pvLocale,boolean pvHidePrice) throws Exception {
Page lvPage= super.getOrderList(pvReq, pvLogin, pvLocale, pvHidePrice);
return lvPage;
}
....
界面出来:
再翻一下第2页,再清除控制台日志, 然后不断切换1,2页, 再看控制台日志输出,已经没有jdbc数据库访问相关的日志了,也就是说,后面的查询数据来源全部来自redis服务器。
再打开redis desktop manager看下缓存的数据: