jedis访问redis学习笔记

时间:2022-09-19 16:46:52

最近在学习redis,在网上查了些文章,利用他人已有的知识,总结写下了这篇文章,大部分内容还是引用别人的文章内容。经过测试发现spring-data-redis现在有的版本只能支持reids 2.6和2.8版本,更高版本尚未支持。还是直接使用jedis比较灵活。

redis

  • redis安装

redis的安装过程在以前的博文中已经详细介绍  linux下安装redis并自启动

  • jedis

jedis下载地址:https://github.com/xetorthio/jedis
             jedis社区地址:https://groups.google.com/forum/#!forum/jedis_redis

最简单的Jedis访问redis

  • jedis官方示例

1、键值读取

       Jedis jedis = new Jedis("redis服务器ip地址", 6379);
jedis.set("foo", "123456");
String value = jedis.get("foo");
System.out.println("____________value="+value);

2、集群读取

       Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
//Jedis Cluster will attempt to discover cluster nodes automatically
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7379));
JedisCluster jc = new JedisCluster(jedisClusterNodes);
jc.set("foo", "bar");
String value = jc.get("foo");

jedis 池和sharding基本示例

redis的基本配置信息

将以下内容放在redis.properties或者文件中,后面有关的.properties文件的内容都跟下面一样的内容。

    redis.host=192.168.1.100
redis.port=6379
redis.pass=123456
redis.default.db=0
redis.timeout=100000//客户端超时时间单位是毫秒
redis.maxActive=300// 最大连接数
redis.maxIdle=100//最大空闲数
redis.maxWait=1000//最大建立连接等待时间
redis.testOnBorrow=true
redis.testOnReturn=true;

java读取配置文件

    ResourceBundle bundle = ResourceBundle.getBundle("redis");
    if (bundle == null) {
        throw new IllegalArgumentException(
                "[redis.properties] is not found!");
    }

redis池

jedisc池需要commons-pool.jar的支持。

  • 池对象的获取与回收

在没有使用spring-data-redis的情况下,需要手工获取池对象,并在使用完毕后放回对象池中。

在使用redis池,需要通过以下代码方式从pool中获取资源。

       jedisPool.getResource()

资源使用完毕后需要放入pool中

      jedisPool.returnResource(jedis);

具体的示例代码

    public class MyJedisPool {
        // jedis池
        private static JedisPool pool;
        
        // 静态代码初始化池配置
        static {
           // 加载redis配置文件
           ResourceBundle bundle = ResourceBundle.getBundle("redis");            if (bundle == null) {
           throw new IllegalArgumentException("[redis.properties] is not found!");
           }            // 创建jedis池配置实例
           JedisPoolConfig config = new JedisPoolConfig();            // 设置池配置项值
           config.setMaxActive(Integer.valueOf(bundle.getString("redis.pool.maxActive")));
           config.setMaxIdle(Integer.valueOf(bundle.getString("redis.pool.maxIdle")));
           config.setMaxWait(Long.valueOf(bundle.getString("redis.pool.maxWait")));
         config.setTestOnBorrow(Boolean.valueOf(bundle.getString("redis.pool.testOnBorrow")));
         config.setTestOnReturn(Boolean.valueOf(bundle.getString("redis.pool.testOnReturn")));
          
//根据配置实例化jedis池
           pool = new JedisPool(config, bundle.getString("redis.ip"), Integer.valueOf(bundle.getString("redis.port")));
        }         /**
         * 测试jedis池方法
         */
        public static void test1() {
           // 从jedis池中获取一个jedis实例
           Jedis jedis = pool.getResource();            // 获取jedis实例后可以对redis服务进行一系列的操作
           jedis.set("name", "xmong");
           System.out.println(jedis.get("name"));            jedis.del("name");
           System.out.println(jedis.exists("name"));            // 释放对象池,即获取jedis实例使用后要将对象还回去
           pool.returnResource(jedis);
        }
    }

redis分布式

  • 分布式配置信息
    #redis1服务器ip #
Redis1.ip=172.30.5.113 #redis2服务器ip #
Redis2.ip=172.30.5.117 #redis服务器端口号#
redis.port=6379
  • 分布式读取方法
    public class MyJedisPool {
        // jedis池
        private static JedisPool pool;         // shardedJedis池
        private static ShardedJedisPool shardPool;         // 静态代码初始化池配置         static {
           // 加载redis配置文件
           ResourceBundle bundle = ResourceBundle.getBundle("redis");            if (bundle == null) {
           throw new IllegalArgumentException("[redis.properties] is not found!");
           }            // 创建jedis池配置实例
           JedisPoolConfig config = new JedisPoolConfig();            // 设置池配置项值
           config.setMaxActive(Integer.valueOf(bundle.getString("redis.pool.maxActive")));
           config.setMaxIdle(Integer.valueOf(bundle.getString("redis.pool.maxIdle")));
           config.setMaxWait(Long.valueOf(bundle.getString("redis.pool.maxWait")));
         config.setTestOnBorrow(Boolean.valueOf(bundle.getString("redis.pool.testOnBorrow")));
         config.setTestOnReturn(Boolean.valueOf(bundle.getString("redis.pool.testOnReturn")));            // 根据配置实例化jedis池
           // pool = new JedisPool(config, bundle.getString("redis.ip"),
           // Integer.valueOf(bundle.getString("redis.port")));            // 创建多个redis共享服务
           JedisShardInfo jedisShardInfo1 = new JedisShardInfo(bundle.getString("redis1.ip"), Integer.valueOf(bundle.getString("redis.port")));
           JedisShardInfo jedisShardInfo2 = new JedisShardInfo(bundle.getString("redis2.ip"), Integer.valueOf(bundle.getString("redis.port")));            List<JedisShardInfo> list = new LinkedList<JedisShardInfo>();
           list.add(jedisShardInfo1);
           list.add(jedisShardInfo2);            // 根据配置文件,创建shared池实例
           shardPool = new ShardedJedisPool(config, list);
        }         /**
         * 测试jedis池方法
         */
        public static void test1() {
           // 从jedis池中获取一个jedis实例
           Jedis jedis = pool.getResource();            // 获取jedis实例后可以对redis服务进行一系列的操作
           jedis.set("name", "xmong");
           System.out.println(jedis.get("name"));            jedis.del("name");
           System.out.println(jedis.exists("name"));            // 释放对象池,即获取jedis实例使用后要将对象还回去
           pool.returnResource(jedis);
        }         /**
         * 测试shardedJedis池方法
         */
        public static void test2() {
           // 从shard池中获取shardJedis实例
           ShardedJedis shardJedis = shardPool.getResource();
    
           // 向redis服务插入两个key-value对象
           shardJedis.set("aaa", "xmong_aaa");
           System.out.println(shardJedis.get("aaa"));            shardJedis.set("zzz", "xmong_zzz");
           System.out.println(shardJedis.get("zzz"));            // 释放资源
           shardPool.returnResource(shardJedis);
        }              public static void main(String[] args) {
           // test1();//执行test1方法
           test2();// 执行test2方法
        }
    }

spinrg 整合redis

spring结合redis配置连接池

	<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxActive" value="32"></property>
<property name="maxIdle" value="6"></property>
<property name="maxWait" value="15000"></property>
<property name="minEvictableIdleTimeMillis" value="300000"></property>
<property name="numTestsPerEvictionRun" value="3"></property>
<property name="timeBetweenEvictionRunsMillis" value="60000"></property>
<property name="whenExhaustedAction" value="1"></property>
</bean>
<bean id="jedisPool" class="redis.clients.jedis.JedisPool" destroy-method="destroy">
<!-- config -->
<constructor-arg ref="jedisPoolConfig"></constructor-arg>
<!-- host -->
<constructor-arg value="127.0.0.1"></constructor-arg>
<!-- port -->
<constructor-arg value="6379"></constructor-arg>
<!-- timeout -->
<constructor-arg value="15000"></constructor-arg>
<!-- password -->
<constructor-arg value="0123456"></constructor-arg>
<!-- database index -->
<constructor-arg value="12"></constructor-arg>
</bean>

测试类

public static void main(String[] args) {
//resources/beans.xml
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:beans.xml");
JedisPool jedisPool = (JedisPool)context.getBean("jedisPool");
Jedis client = jedisPool.getResource();
try{
client.select(0);
client.set("k1", "v1");
System.out.println(client.get("k1"));
}catch(Exception e){
e.printStackTrace();
}finally{
jedisPool.returnResource(client);//must be
}
}

new ClassPathXmlApplicationContext("classpath:beans.xml");是直接读取beans.xml文件,因此需要将上面的配置内容放在beans.xml中,来获取bean对象实例。

spring 结合redis sharding

    <context:property-placeholder location="classpath:redis.properties" />
<context:component-scan base-package="com.d.work.main">
</context:component-scan>
<context:component-scan base-package="com.d.work.redis">
</context:component-scan>
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxActive" value="50" />
<property name="maxIdle" value="8" />
<property name="maxWait" value="1000" />
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="true"/>
<!-- <property name="testWhileIdle" value="true"/> -->
</bean> <bean id="shardedJedisPool" class="redis.clients.jedis.ShardedJedisPool" scope="singleton">
<constructor-arg index="0" ref="jedisPoolConfig" />
<constructor-arg index="1">
<list>
<bean class="redis.clients.jedis.JedisShardInfo">
<constructor-arg name="host" value="${redis.host}" />
<constructor-arg name="port" value="${redis.port}" />
<constructor-arg name="timeout" value="${redis.timeout}" />
<constructor-arg name="weight" value="1" />
</bean>
</list>
</constructor-arg>
</bean>

Spring-data-redis

spring 提供jsmTemplement,jdbcTemplement,redisTemplement等类似模板。spring 通过context:property-placeholder实现导入配置文件,context:property-placeholder 标签用来导入properties文件。从而替换${redis.maxIdle}这样的变量。要使用spring-data-redis,需要下载spring-data-redis-1.5.1.RELEASE.jar

spring-data-redis针对redis提供了以下的特性

  • 连接池自动管理

提供了一个高度封装的“RedisTemplate”类

  • 针对jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口

ValueOperations:简单K-V操作
                  SetOperations:set类型数据操作
                  ZSetOperations:zset类型数据操作
                  HashOperations:针对map类型的数据操作
                  ListOperations:针对list类型的数据操作

  • 提供了对key的“bound”(绑定)便捷化操作API,可以通过bound封装指定的key,然后进行一系列的操作而无须“显式”的再次指定Key,即BoundKeyOperations:

BoundValueOperations
                BoundSetOperations
                BoundListOperations
                BoundSetOperations
                BoundHashOperations

  • 将事务操作封装,有容器控制。
  • 针对数据的“序列化/反序列化”,提供了多种可选择策略(RedisSerializer)

JdkSerializationRedisSerializer:POJO对象的存取场景,使用JDK本身序列化机制,将pojo类通过ObjectInputStream/ObjectOutputStream进行序列化操作,最终redis-server中将存储字节序列。是目前最常用的序列化策略。
                StringRedisSerializer:Key或者value为字符串的场景,根据指定的charset对数据的字节序列编码成string,是“new String(bytes, charset)”和“string.getBytes(charset)”的直接封装。是最轻量级和高效的策略。
                JacksonJsonRedisSerializer:jackson-json工具提供了javabean与json之间的转换能力,可以将pojo实例序列化成json格式存储在redis中,也可以将json格式的数据转换成pojo实例。因为jackson工具在序列化和反序列化时,需要明确指定Class类型,因此此策略封装起来稍微复杂。【需要jackson-mapper-asl工具支持】
                OxmSerializer:提供了将javabean与xml之间的转换能力,目前可用的三方支持包括jaxb,apache-xmlbeans;redis存储的数据将是xml工具。不过使用此策略,编程将会有些难度,而且效率最低;不建议使用。【需要spring-oxm模块的支持】
                针对“序列化和发序列化”中JdkSerializationRedisSerializer和StringRedisSerializer是最基础的策略,原则上,我们可以将数据存储为任何格式以便应用程序存取和解析(其中应用包括app,hadoop等其他工具),不过在设计时仍然不推荐直接使用“JacksonJsonRedisSerializer”和“OxmSerializer”,因为无论是json还是xml,他们本身仍然是String。
                如果你的数据需要被第三方工具解析,那么数据应该使用StringRedisSerializer而不是JdkSerializationRedisSerializer。
                如果你的数据格式必须为json或者xml,那么在编程级别,在redisTemplate配置中仍然使用StringRedisSerializer,在存储之前或者读取之后,使用“SerializationUtils”工具转换转换成json或者xml,请参见下文实例。

  • 基于设计模式,和JMS开发思路,将pub/sub的API设计进行了封装,使开发更加便捷。
  • spring-data-redis中,并没有对sharding提供良好的封装,如果你的架构是基于sharding,那么你需要自己去实现,这也是sdr和jedis相比,唯一缺少的特性。

spinrg-data-redis配置与调用

示例一

    <bean id="propertyConfigurerRedis" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="order" value="1" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="locations">
<list>
<value>classpath:config/redis-manager-config.properties</value>
</list>
</property>
</bean> <!-- jedis pool配置 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxActive" value="${redis.maxActive}" />
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="maxWait" value="${redis.maxWait}" />
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean> <!-- spring data redis -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="usePool" value="true"></property>
<property name="hostName" value="${redis.host}" />
<property name="port" value="${redis.port}" />
<property name="password" value="${redis.pass}" />
<property name="timeout" value="${redis.timeout}" />
<property name="database" value="${redis.default.db}"></property>
<constructor-arg index="0" ref="jedisPoolConfig" />
</bean> <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory" />
</bean>
public class RedisBase {  

    private StringRedisTemplate template;  

    /**
* @return the template
*/
public StringRedisTemplate getTemplate() {
return template;
} /**
* @param template the template to set
*/
public void setTemplate(StringRedisTemplate template) {
this.template = template;
} }

示例二

	<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxActive" value="32"></property>
<property name="maxIdle" value="6"></property>
<property name="maxWait" value="15000"></property>
<property name="minEvictableIdleTimeMillis" value="300000"></property>
<property name="numTestsPerEvictionRun" value="3"></property>
<property name="timeBetweenEvictionRunsMillis" value="60000"></property>
<property name="whenExhaustedAction" value="1"></property>
</bean>
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy">
<property name="poolConfig" ref="jedisPoolConfig"></property>
<property name="hostName" value="127.0.0.1"></property>
<property name="port" value="6379"></property>
<property name="password" value="0123456"></property>
<property name="timeout" value="15000"></property>
<property name="usePool" value="true"></property>
</bean>
<bean id="jedisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"></property>
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="valueSerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
</property>
</bean>
public class SpringDataRedisTestMain {

	/**
* @param args
*/
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-redis-beans.xml");
RedisTemplate redisTemplate = (RedisTemplate)context.getBean("jedisTemplate");
//其中key采取了StringRedisSerializer
//其中value采取JdkSerializationRedisSerializer
ValueOperations<String, User> valueOper = redisTemplate.opsForValue();
User u1 = new User("zhangsan",12);
User u2 = new User("lisi",25);
valueOper.set("u:u1", u1);
valueOper.set("u:u2", u2);
System.out.println(valueOper.get("u:u1").getName());
System.out.println(valueOper.get("u:u2").getName());
} /**
* 如果使用jdk序列化方式,bean必须实现Serializable,且提供getter/setter方法
* @author qing
*
*/
static class User implements Serializable{ /**
*
*/
private static final long serialVersionUID = -3766780183428993793L;
private String name;
private Date created;
private int age;
public User(){}
public User(String name,int age){
this.name = name;
this.age = age;
this.created = new Date();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} } }

如果你使用过jedisPool连接池,在数据操作之前,你需要pool.getResource()即从连接池中获取“链接资源”(Jedis),在操作之后,你需要(必须)调用pool.returnResource()将资源归还个连接池。但是,spring-data-redis中,我们似乎并没有直接操作pool,那么spring是如何做到pool管理的呢??一句话:spring的“看门绝技”--callback。

public <T> T execute(RedisCallback<T> action):这个方法是redisTemplate中执行操作的底层方法,任何基于redisTemplate之上的调用(比如,valueOperations)最终都会被封装成RedisCallback,redisTemplate在execute方法中将会直接使用jedis客户端API进行与server通信,而且在如果使用了连接池,则会在操作之后执行returnSource。

java读取bean方式

方式一

	ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-redis-beans.xml");
RedisTemplate redisTemplate = (RedisTemplate)context.getBean("jedisTemplate");

方式二

        ApplicationContext ctx = new FileSystemXmlApplicationContext("classpath:setup/applicationContext.xml");
cachedClient = (MemCachedClient)ctx.getBean("memcachedClient");

Spring-data-redis: pub/sub消息订阅

redis可以用来做消息订阅操作。

第一步配置

	<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxActive" value="32"></property>
<property name="maxIdle" value="6"></property>
<property name="maxWait" value="15000"></property>
<property name="minEvictableIdleTimeMillis" value="300000"></property>
<property name="numTestsPerEvictionRun" value="3"></property>
<property name="timeBetweenEvictionRunsMillis" value="60000"></property>
<property name="whenExhaustedAction" value="1"></property>
</bean>
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy">
<property name="poolConfig" ref="jedisPoolConfig"></property>
<property name="hostName" value="127.0.0.1"></property>
<property name="port" value="6379"></property>
<property name="password" value="0123456"></property>
<property name="timeout" value="15000"></property>
<property name="usePool" value="true"></property>
</bean>
<bean id="jedisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"></property>
<property name="defaultSerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
</bean> <bean id="topcMessageListener" class="com.sample.redis.sdr.TopicMessageListener">
<property name="redisTemplate" ref="jedisTemplate"></property>
</bean>
<bean id="topicContainer" class="org.springframework.data.redis.listener.RedisMessageListenerContainer" destroy-method="destroy">
<property name="connectionFactory" ref="jedisConnectionFactory"/>
<property name="taskExecutor"><!-- 此处有个奇怪的问题,无法正确使用其他类型的Executor -->
<bean class="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler">
<property name="poolSize" value="3"></property>
</bean>
</property>
<property name="messageListeners">
<map>
<entry key-ref="topcMessageListener">
<bean class="org.springframework.data.redis.listener.ChannelTopic">
<constructor-arg value="user:topic"/>
</bean>
</entry>
</map>
</property>
</bean>

第二部:发布消息

String channel = "user:topic";
//其中channel必须为string,而且“序列化”策略也是StringSerializer
//消息内容,将会根据配置文件中指定的valueSerializer进行序列化
//本例中,默认全部采用StringSerializer
//那么在消息的subscribe端也要对“发序列化”保持一致。
redisTemplate.convertAndSend(channel, "from app 1");

第三部:消息接收

public class TopicMessageListener implements MessageListener {

	private RedisTemplate redisTemplate;

	public void setRedisTemplate(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
} @Override
public void onMessage(Message message, byte[] pattern) {
byte[] body = message.getBody();//请使用valueSerializer
byte[] channel = message.getChannel();
//请参考配置文件,本例中key,value的序列化方式均为string。
//其中key必须为stringSerializer。和redisTemplate.convertAndSend对应
String itemValue = (String)redisTemplate.getValueSerializer().deserialize(body);
String topic = (String)redisTemplate.getStringSerializer().deserialize(channel);
//...
}
}

spring-data-redis 事物处理

以下示例显示spring-data-redis实现事物处理,并通过回调方法实现返回数据

    //execute a transaction
    List<Object> txResults = redisTemplate.execute(new SessionCallback<List<Object>>() {
      public List<Object> execute(RedisOperations operations) throws DataAccessException {
        operations.multi();
        operations.opsForSet().add("key", "value1");         // This will contain the results of all ops in the transaction
        return operations.exec();
      }
    });
    System.out.println("Number of items added to set: " + txResults.get(0));

Spring-data-redis: serializer实例

sdr提供了4种内置的serializer:

1、JdkSerializationRedisSerializer:使用JDK的序列化手段(serializable接口,ObjectInputStrean,ObjectOutputStream),数据以字节流存储

2、StringRedisSerializer:字符串编码,数据以string存储

3、JacksonJsonRedisSerializer:json格式存储

4、OxmSerializer:xml格式存储

其中JdkSerializationRedisSerializer和StringRedisSerializer是最基础的序列化策略,其中“JacksonJsonRedisSerializer”与“OxmSerializer”都是基于stirng存储,因此它们是较为“高级”的序列化(最终还是使用string解析以及构建java对象)。

RedisTemplate中需要声明4种serializer,默认为“JdkSerializationRedisSerializer”:

1) keySerializer :对于普通K-V操作时,key采取的序列化策略
    2) valueSerializer:value采取的序列化策略
    3) hashKeySerializer: 在hash数据结构中,hash-key的序列化策略
    4) hashValueSerializer:hash-value的序列化策略

无论如何,建议key/hashKey采用StringRedisSerializer。

       配置JdkSerializationRedisSerializer/StringRedisSerializer

<bean id="jedisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"></property>
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="hashKeySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="valueSerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
</property>
<property name="hashValueSerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
</property>
</bean>
ValueOperations<String, User> valueOper = redisTemplate.opsForValue();
User user = new User("zhangsan",12);
valueOper.set("user:1", user);
System.out.println(valueOper.get("user:1").getName());

题外话

spring framework4.X.X版本与spring framework3.X.X有些区别:

spring framework 4.X.X需要jackjson2.0,同时 org.springframework.http.converter.json.MappingJacksonHttpMessageConverter改为 MappingJacksonHttpMessageConverter已经改为MappingJackson2HttpMessageConverter
 
            spring framework 4.X.X配置中使用
            <mvc:annotation-driven/>

不再需要手工配置bean

	<bean class ="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" >
<property name="messageConverters">
<list>
<ref bean="mappingJackson2HttpMessageConverter" />
</list>
</property>
</bean> <bean name="mappingJackson2HttpMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
</list>
</property>
</bean>

参考资料

http://snowolf.iteye.com/blog/1630697

http://my.oschina.net/gccr/blog/307725

http://blog.163.com/asd_wll/blog/static/210310402013654528316/

http://wenku.baidu.com/link?url=fuS8aw93_4_Qvv8WBgazt5eZGiDhv1Np5vCyB8qBUVdWIUxI47IaA5opzI3vwhWth7MrF1KiJn_o1aBvWmFdeNxbmbcSnyCTEd54C0iLLEC

http://my.oschina.net/gccr/blog/307725

http://shift-alt-ctrl.iteye.com/blog/1886831

http://www.cnblogs.com/liuling/p/2014-4-19-04.html

http://www.cnblogs.com/tankaixiong/p/3660075.html

http://blog.csdn.net/neubuffer/article/details/17003909

http://blog.csdn.net/liuzhigang1237/article/details/8283797
             http://shift-alt-ctrl.iteye.com/blog/1887370
             http://shift-alt-ctrl.iteye.com/blog/1887473
             http://shift-alt-ctrl.iteye.com/blog/1887644
             http://shift-alt-ctrl.iteye.com/blog/1887700
             http://shift-alt-ctrl.iteye.com/blog/1886831
             http://shift-alt-ctrl.iteye.com/blog/1885910

http://www.open-open.com/lib/view/open1385173126448.html

http://blog.csdn.net/A_lele123/article/details/43406547

http://javacrazyer.iteye.com/blog/1840161

http://redis.readthedocs.org/en/2.4/index.html