Java Spring mvc 操作 Redis 及 Redis 集群

本文原创,转载请注明:http://www.cnblogs.com/fengzheng/p/5941953.html

关于 Redis 集群搭建可以参考我的另一篇文章 Redis 集群搭建与简单使用

Redis 是什么,能做什么

Redis 是一个开源(BSD 许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串哈希表列表集合有序集合位图hyperloglogs等数据类型。内置复制、Lua 脚本、LRU 收回、事务以及不同级别磁盘持久化功能,同时通过 Redis Sentinel 提供高可用,通过 Redis Cluster 提供自动分区。( 摘自 Redis 官网)

作为内存数据库,在现代互联网 web 系统中,还是主要将 Redis 作为缓存使用。大型互联网 Web 系统对性能要求很高,而在前端和数据层之间增加数据缓存已成为必不可少的手段之一,当前比较流行的两个技术就是 Redis 和 Memcached,至于两者有什么区别,不是本文要说的内容。本文主要讲 Java web 如何操作 Redis 及 Redis 集群。

一般 Java 程序操作 Redis

Redis 提供了多种语言的客户端,在 Java 中最流行的是 Jedis 。访问可查看源码及使用方式。目前 Jedis 最新版本是 2.9.0。无论是单机还是集群,Jedis 都有很详细的说明和实例代码,这里只做简单说明。如果用 Maven 做包管理,需要引用  jedis 包,本例使用最新的 2.9.0 版本,如下:

1
2
3
4
5
<dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      <version>2.9.0</version>
</dependency>  

操作 Redis 单机

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**

  • Created by fengdezitai on 2016/10/9.
    */
    public class JedisClient {

    private static final String host= "192.168.31.121";

    private static final JedisClient jedisClient = new JedisClient();

    private Jedis jedis = null;
    /**

    • 私有构造函数
      */
      private JedisClient(){}

    public static JedisClient getInstance(){
    return jedisClient;
    }

    private JedisPoolConfig getPoolConfig(){
    JedisPoolConfig jedisPoolConfig
    = new JedisPoolConfig();
    jedisPoolConfig.setMaxIdle(
    10);
    jedisPoolConfig.setMaxTotal(
    100);
    jedisPoolConfig.setMaxWaitMillis(
    3000);
    return jedisPoolConfig;
    }

    /**

    • 添加

    • @param key

    • @param value

    • @return

    • @throws Exception
      */
      public Boolean add(String key,String value) throws Exception{
      JedisPool pool
      = new JedisPool(getPoolConfig(),host);
      Jedis jedis
      = null;
      try {
      jedis
      = pool.getResource();
      if(jedis.exists(key)){
      throw new Exception(String.format("key (%s) 已存在",key));
      }
      jedis.set(key,value);

      }catch (Exception e){
      throw e;
      }
      finally {
      if(jedis!=null){
      jedis.close();
      }
      }
      pool.destroy();
      return true;
      }

    /**

    • 获取值
    • @param key
    • @return
    • @throws Exception
      */
      public String get(String key) throws Exception{
      JedisPool pool
      = new JedisPool(getPoolConfig(),host);
      Jedis jedis
      = null;
      String result
      = "";
      try {
      jedis
      = pool.getResource();
      result
      = jedis.get(key);
      }
      catch (Exception e){
      throw e;
      }
      finally {
      if(jedis!=null){
      jedis.close();
      }
      }
      pool.destroy();
      return result;
      }

    public static void main(String[] args) {
    JedisClient jedisClient
    = JedisClient.getInstance();
    try {
    /Boolean result = jedisClient.add("hello", "redis1");
    if(result){
    System.out.println("success");
    }
    /

         System.out.println(jedisClient.get(</span>"hello"<span style="color: rgba(0, 0, 0, 1)">));
     }</span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e){
         e.printStackTrace();
     }
    

    }
    }

 

操作 redis 集群

import redis.clients.jedis.*;
import java.util.HashSet;
import java.util.Set;

/**

  • Created by fengdezitai on 2016/10/13.
    */
    public class JedisClusterClient {

    private static int count = 0;

    private static final JedisClusterClient redisClusterClient = new JedisClusterClient();

    /**

    • 私有构造函数
      */
      private JedisClusterClient(){}

    public static JedisClusterClient getInstance() {
    return redisClusterClient;
    }

    private JedisPoolConfig getPoolConfig(){
    JedisPoolConfig config
    = new JedisPoolConfig();
    config.setMaxTotal(
    1000);
    config.setMaxIdle(
    100);
    config.setTestOnBorrow(
    true);
    return config;
    }

    public void SaveRedisCluster() {
    Set
    <HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
    jedisClusterNodes.add(
    new HostAndPort("192.168.31.245", 7000));
    jedisClusterNodes.add(
    new HostAndPort("192.168.31.245", 7001));
    jedisClusterNodes.add(
    new HostAndPort("192.168.31.245", 7002));
    jedisClusterNodes.add(
    new HostAndPort("192.168.31.210", 7003));
    jedisClusterNodes.add(
    new HostAndPort("192.168.31.210", 7004));
    jedisClusterNodes.add(
    new HostAndPort("192.168.31.210", 7005));

     JedisCluster jc </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> JedisCluster(jedisClusterNodes,getPoolConfig());
     jc.set(</span>"cluster", "this is a redis cluster"<span style="color: rgba(0, 0, 0, 1)">);
     String result </span>= jc.get("cluster"<span style="color: rgba(0, 0, 0, 1)">);
     System.out.println(result);
    

    }

    public static void main(String[] args) {
    JedisClusterClient jedisClusterClient
    = JedisClusterClient.getInstance();
    jedisClusterClient.SaveRedisCluster();
    }
    }  

 

Spring mvc 操作 Redis

在 Spring mvc 中操作 Redis ,首先当然要搭好 Spring mvc 框架了。以下是在假设 Spring mvc 环境已经架好的情况下。本例中 Spring 版本为 4.3.2 RELEASE。关于 Spring 的 maven 引用如下:

!-- spring 版本号 -->
<spring.version>4.3.2.RELEASE</spring.version>

<!-- spring 核心包 -->
<!-- springframe start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>

&lt;dependency&gt;
  &lt;groupId&gt;org.springframework&lt;/groupId&gt;
  &lt;artifactId&gt;spring-web&lt;/artifactId&gt;
  &lt;version&gt;${spring.version}&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
  &lt;groupId&gt;org.springframework&lt;/groupId&gt;
  &lt;artifactId&gt;spring-oxm&lt;/artifactId&gt;
  &lt;version&gt;${spring.version}&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
  &lt;groupId&gt;org.springframework&lt;/groupId&gt;
  &lt;artifactId&gt;spring-tx&lt;/artifactId&gt;
  &lt;version&gt;${spring.version}&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
  &lt;groupId&gt;org.springframework&lt;/groupId&gt;
  &lt;artifactId&gt;spring-jdbc&lt;/artifactId&gt;
  &lt;version&gt;${spring.version}&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
  &lt;groupId&gt;org.springframework&lt;/groupId&gt;
  &lt;artifactId&gt;spring-webmvc&lt;/artifactId&gt;
  &lt;version&gt;${spring.version}&lt;/version&gt;
  &lt;exclusions&gt;
    &lt;exclusion&gt;
      &lt;groupId&gt;commons-logging&lt;/groupId&gt;
      &lt;artifactId&gt;commons-logging&lt;/artifactId&gt;
    &lt;/exclusion&gt;
  &lt;/exclusions&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
  &lt;groupId&gt;org.springframework&lt;/groupId&gt;
  &lt;artifactId&gt;spring-aop&lt;/artifactId&gt;
  &lt;version&gt;${spring.version}&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
  &lt;groupId&gt;org.springframework&lt;/groupId&gt;
  &lt;artifactId&gt;spring-context-support&lt;/artifactId&gt;
  &lt;version&gt;${spring.version}&lt;/version&gt;
&lt;/dependency&gt;


&lt;dependency&gt;
  &lt;groupId&gt;org.springframework&lt;/groupId&gt;
  &lt;artifactId&gt;spring-test&lt;/artifactId&gt;
  &lt;version&gt;${spring.version}&lt;/version&gt;
&lt;/dependency&gt;
&lt;!-- springframe end --&gt;</pre>

 

操作 Redis 单机

只用 Jedis 自己实现注入(区别于下面的引用 spring-data-redis) 

把前面的 JedisClient 代码拿过来引用即可,只需实现一个访问 Redis 的 Service ,就可以集成到 Spring mvc 。Service 代码如下:

import org.springframework.stereotype.Service;
import util.JedisClient;

/**

  • Created by fengdezitai on 2016/10/9.
    */
    @Service
    public class RedisService {

    public String get(String key) throws Exception{
    JedisClient jedisClient
    = JedisClient.getInstance(); //上面实现的 JedisClient
    String result = "";
    try {
    result
    = jedisClient.get("hello");
    }
    catch (Exception e){
    throw e;
    }
    return result;
    }
    }

 

Controller 实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Controller
@RequestMapping(value = "redisAllInOne")
public class RedisAllInOneController {
 
    @Autowired
    private RedisService redisService;
 
    @RequestMapping(value = "get",method = RequestMethod.GET)
    @ResponseBody
    public Object getByMyService(String key){
        try {
            String result = redisService.get(key);
            return result;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}  

用 spring-data-redis 包做集成

上面是自己实现的注入,这里用 spring-data-redis 进行集成,只需简单配置即可,需要引用 maven 包如下,版本为目前最新版 1.7.2.RELEASE:

1
2
3
4
5
<dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-redis</artifactId>
      <version>1.7.2.RELEASE</version>
    </dependency>

使用 spring-data-redis ,即省去了自己实现注入的过程,通过它提供的一些配置,即可实现连接池配置、RedisTemplate 配置、JedisConnectionFactory 配置;通过 JedisConnectionFactory 可配置连接池参数、redis 服务器、端口、密码、超时时间、database 索引等;RedisTemplate 即注入的 bean ,可以使用 RedisTemplate 自动注入的实体进行 redis 的一系列操作,具体看配置;

redis 服务属性配置文件:

1
2
3
4
5
6
7
redis.maxIdle=300
redis.maxWait=3000
redis.testOnBorrow=true
redis.host=192.168.31.121
redis.port=6379
redis.password=password
redis.timeout=3000

spring-data-redis xml 配置文件 redis-context.xml:

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
34
35
36
37
38
39
40
41
<!-- jedis 连接池 配置 -->
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig" >
        <property name="maxIdle" value="${redis.maxIdle}" />
        <property name="maxWaitMillis" value="${redis.maxWait}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    </bean>
    <!-- redis服务器中心 -->
    <bean id="connectionFactory"  class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" >
        <property name="poolConfig" ref="poolConfig" />
        <property name="port" value="${redis.port}" />
        <property name="hostName" value="${redis.host}" />
        <!--<property name="password" value="${redis.password}" />-->
        <property name="timeout" value="${redis.timeout}" ></property>
        <property name="database" value="1"></property>
    </bean>
 
    <bean id="commonRedisTemplate" class="org.springframework.data.redis.core.RedisTemplate" >
        <property name="connectionFactory" ref="connectionFactory" />
        <property name="keySerializer" ref="stringRedisSerializer" />
        <property name="hashKeySerializer" ref="stringRedisSerializer" />
        <property name="valueSerializer" ref="stringRedisSerializer" />
        <property name="hashValueSerializer" ref="stringRedisSerializer" />
    </bean>
 
    <bean id="connectionFactory1"  class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" >
        <property name="poolConfig" ref="poolConfig" />
        <property name="port" value="${redis.port}" />
        <property name="hostName" value="${redis.host}" />
        <!--<property name="password" value="${redis.password}" />-->
        <property name="timeout" value="${redis.timeout}" ></property>
        <property name="database" value="2"></property>
    </bean>
 
    <bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer" />
    <bean id="cacheRedisTemplate" class="org.springframework.data.redis.core.RedisTemplate" >
        <property name="connectionFactory" ref="connectionFactory1" />
        <property name="keySerializer" ref="stringRedisSerializer" />
        <property name="hashKeySerializer" ref="stringRedisSerializer" />
        <property name="valueSerializer" ref="stringRedisSerializer" />
        <property name="hashValueSerializer" ref="stringRedisSerializer" />
    </bean>

之后在 spring 配置文件中引用以上文件:

1
<import resource="redis-context.xml" />  

解释一下上面的配置:

poolConfig 即配置 redis 连接池,之后配置了两个 JedisConnectionFactory 和 RedisTemplate ,一个 RedisTemplate 对应一个 JedisConnectionFactory ,这样可以配置根据场景配置不同的 Redis 连接,比如超时时间要求不一致、database 0-15 可以存储不同的数据等。这里就配置了 database 1 和 2 ,调用 commonRedisTemplate 会存到 database1 ,调用 cacheRedisTemplate 会存到 database2。

之后在 Service 层即可注入并引用这两个 RedisTemplate ,如下代码:

import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import java.io.*;

@Repository
public class RedisCache {<br>  
@Resource(name
= "cacheRedisTemplate")
private RedisTemplate<String, String> cacheRedisTemplate;

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> put(Object key, Object value) {
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(<span style="color: rgba(0, 0, 255, 1)">null</span> ==<span style="color: rgba(0, 0, 0, 1)"> value) {
        </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
    }

    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(value <span style="color: rgba(0, 0, 255, 1)">instanceof</span><span style="color: rgba(0, 0, 0, 1)"> String) {
        </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(StringUtils.isEmpty(value.toString())) {
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
        }
    }

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> TODO Auto-generated method stub</span>
    <span style="color: rgba(0, 0, 255, 1)">final</span> String keyf = key + ""<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">final</span> Object valuef =<span style="color: rgba(0, 0, 0, 1)"> value;
    </span><span style="color: rgba(0, 0, 255, 1)">final</span> <span style="color: rgba(0, 0, 255, 1)">long</span> liveTime = 86400<span style="color: rgba(0, 0, 0, 1)">;

    cacheRedisTemplate.execute(</span><span style="color: rgba(0, 0, 255, 1)">new</span> RedisCallback&lt;Long&gt;<span style="color: rgba(0, 0, 0, 1)">() {
        </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Long doInRedis(RedisConnection connection)
                </span><span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> DataAccessException {
            </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] keyb =<span style="color: rgba(0, 0, 0, 1)"> keyf.getBytes();
            </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] valueb =<span style="color: rgba(0, 0, 0, 1)"> toByteArray(valuef);
            connection.set(keyb, valueb);
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (liveTime &gt; 0<span style="color: rgba(0, 0, 0, 1)">) {
                connection.expire(keyb, liveTime);
            }
            </span><span style="color: rgba(0, 0, 255, 1)">return</span> 1L<span style="color: rgba(0, 0, 0, 1)">;
        }
    });
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Object get(Object key) {
    </span><span style="color: rgba(0, 0, 255, 1)">final</span> String keyf =<span style="color: rgba(0, 0, 0, 1)"> (String) key;
    Object object;
    object </span>= cacheRedisTemplate.execute(<span style="color: rgba(0, 0, 255, 1)">new</span> RedisCallback&lt;Object&gt;<span style="color: rgba(0, 0, 0, 1)">() {
        </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Object doInRedis(RedisConnection connection)
                </span><span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> DataAccessException {

            </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] key =<span style="color: rgba(0, 0, 0, 1)"> keyf.getBytes();
            </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] value =<span style="color: rgba(0, 0, 0, 1)"> connection.get(key);
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (value == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
                </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            }
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> toObject(value);

        }
    });

    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> object;
}

</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
 * 描述 : &lt;byte[]转Object&gt;. &lt;br&gt;
 * &lt;p&gt;
 * &lt;使用方法说明&gt;
 * &lt;/p&gt;
 *
 * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> bytes
 * </span><span style="color: rgba(128, 128, 128, 1)">@return</span>
 <span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">private</span> Object toObject(<span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)">[] bytes) {
    Object obj </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
        ByteArrayInputStream bis </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ByteArrayInputStream(bytes);
        ObjectInputStream ois </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ObjectInputStream(bis);
        obj </span>=<span style="color: rgba(0, 0, 0, 1)"> ois.readObject();
        ois.close();
        bis.close();
    } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException ex) {
        ex.printStackTrace();
    } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (ClassNotFoundException ex) {
        ex.printStackTrace();
    }
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> obj;
}

</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)">[] toByteArray(Object obj) {
    </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] bytes = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
    ByteArrayOutputStream bos </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ByteArrayOutputStream();
    </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
        ObjectOutputStream oos </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ObjectOutputStream(bos);
        oos.writeObject(obj);
        oos.flush();
        bytes </span>=<span style="color: rgba(0, 0, 0, 1)"> bos.toByteArray();
        oos.close();
        bos.close();
    } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException ex) {
        ex.printStackTrace();
    }
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> bytes;
}

}

 

最后在 Controller 中调用即可

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
@Autowired
private RedisCache redisCache;
 
 
@RequestMapping(value = "get", method = RequestMethod.GET)
@ResponseBody
public Object getByMyService(String key) {
    try {
        String result = redisService.get(key);
        return result;
    catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}
 
@RequestMapping(value = "save", method = RequestMethod.GET)
@ResponseBody
public Object save() {
    Token token = new Token();
    token.setAccess_token("token");
    token.setExpires_in(1000);
    try {
        redisCache.put("token", token);
    catch (Exception e) {
        e.printStackTrace();
    }
    return "ok";
}  

操作 Redis 集群

只用 Jedis 自己实现注入(区别于下面的引用 spring-data-redis)

把前面的 JedisClusterClient 代码拿过来引用即可,只需实现一个访问 Redis 的 Service ,就可以集成到 Spring mvc 。Service 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import org.springframework.stereotype.Service;
import util.JedisClusterClient;
 
/**
 * Created by fengdezitai on 2016/10/13.
 */
@Service
public class RedisClusterService {
 
    public void save() throws Exception{
        //调用 JedisClusterClient 中的方法
        JedisClusterClient jedisClusterClient = JedisClusterClient.getInstance();
        try {
            jedisClusterClient.SaveRedisCluster();
        }catch (Exception e){
            throw e;
        }
    }
}

最后在 Controller 中调用实现的 Service 即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Controller
@RequestMapping(value = "redisCluster")
public class RedisClusterController {
 
    @Autowired
    private RedisClusterService redisClusterService;
 
    @RequestMapping(value = "save",method = RequestMethod.GET)
    @ResponseBody
    public Object save(){
        try{
            redisClusterService.save();
        }catch (Exception e){
            e.printStackTrace();
            return String.format("error: %s",e.getMessage());
        }
        return "ok";
    }
}  

用 spring-data-redis 包做集成 

Spring 和 spring-data-redis maven 包引用和前面一致,之所以引用 spring-data-redis 1.7.2.RELEASE,是因为目前只有这个最新版本才支持集群操作。

redis 集群服务属性配置

1
2
3
4
redis.maxIdle=300
redis.maxWait=3000
redis.testOnBorrow=false
redis.timeout=3000

spring-data-redis xml 集群配置文件 redis-cluster-context.xml

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!-- 连接池 配置 -->
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig" >
        <property name="maxIdle" value="${redis.maxIdle}" />
        <property name="maxWaitMillis" value="${redis.maxWait}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    </bean>
 
 
    <bean id="redisClusterConfig" class="org.springframework.data.redis.connection.RedisClusterConfiguration">
        <property name="maxRedirects" value="3"></property>
        <property name="clusterNodes">
            <set>
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="192.168.31.245"></constructor-arg>
                    <constructor-arg name="port" value="7000"></constructor-arg>
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="192.168.31.245"></constructor-arg>
                    <constructor-arg name="port" value="7001"></constructor-arg>
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="192.168.31.245"></constructor-arg>
                    <constructor-arg name="port" value="7002"></constructor-arg>
                </bean>
                 <bean class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="192.168.31.210"></constructor-arg>
                    <constructor-arg name="port" value="7003"></constructor-arg>
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="192.168.31.210"></constructor-arg>
                    <constructor-arg name="port" value="7004"></constructor-arg>
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="192.168.31.210"></constructor-arg>
                    <constructor-arg name="port" value="7005"></constructor-arg>
                </bean>
            </set>
        </property>
    </bean>
 
    <bean id="redis4CacheConnectionFactory"
          class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <constructor-arg name="clusterConfig" ref="redisClusterConfig" />
        <property name="timeout" value="${redis.timeout}" />
        <property name="poolConfig" ref="poolConfig"/>
    </bean>
 
 
    <bean name="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer" />
    <bean id="clusterRedisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="redis4CacheConnectionFactory" />
        <property name="keySerializer" ref="stringRedisSerializer" />
        <property name="hashKeySerializer" ref="stringRedisSerializer" />
        <property name="valueSerializer" ref="stringRedisSerializer" />
        <property name="hashValueSerializer" ref="stringRedisSerializer" />
    </bean>

之后在 Spring 配置文件中引用

1
<import resource="redis-cluster-context.xml" />

解释以上配置

poolConfig 是连接池配置,redisClusterConfig 配置了 Redis 集群的各个节点(节点 host 和 port 最好写在属性配置文件中),集群搭建可见 我的 另一篇博客 。然后下面和单机配置一样了,一对 JedisConnectionFactory 和 RedisTemplate 。

之后在 Service 层即可注入并引用这个 RedisTemplate,代码如下:

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;

import java.io.*;

/**

  • Created by fengdezitai on 2016/9/29.
    */
    @Repository
    public class RedisClusterCache {

    @Autowired
    private RedisTemplate clusterRedisTemplate;

    public void put(Object key, Object value) {
    if(null == value) {
    return;
    }

     </span><span style="color: rgba(0, 0, 255, 1)">if</span>(value <span style="color: rgba(0, 0, 255, 1)">instanceof</span><span style="color: rgba(0, 0, 0, 1)"> String) {
         </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(StringUtils.isEmpty(value.toString())) {
             </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
         }
     }
    
     </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> TODO Auto-generated method stub</span>
     <span style="color: rgba(0, 0, 255, 1)">final</span> String keyf = key + ""<span style="color: rgba(0, 0, 0, 1)">;
     </span><span style="color: rgba(0, 0, 255, 1)">final</span> Object valuef =<span style="color: rgba(0, 0, 0, 1)"> value;
     </span><span style="color: rgba(0, 0, 255, 1)">final</span> <span style="color: rgba(0, 0, 255, 1)">long</span> liveTime = 86400<span style="color: rgba(0, 0, 0, 1)">;
    
     clusterRedisTemplate.execute(</span><span style="color: rgba(0, 0, 255, 1)">new</span> RedisCallback&lt;Long&gt;<span style="color: rgba(0, 0, 0, 1)">() {
         </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Long doInRedis(RedisConnection connection)
                 </span><span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> DataAccessException {
             </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] keyb =<span style="color: rgba(0, 0, 0, 1)"> keyf.getBytes();
             </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] valueb =<span style="color: rgba(0, 0, 0, 1)"> toByteArray(valuef);
             connection.set(keyb, valueb);
             </span><span style="color: rgba(0, 0, 255, 1)">if</span> (liveTime &gt; 0<span style="color: rgba(0, 0, 0, 1)">) {
                 connection.expire(keyb, liveTime);
             }
             </span><span style="color: rgba(0, 0, 255, 1)">return</span> 1L<span style="color: rgba(0, 0, 0, 1)">;
         }
     });
    

    }

    public Object get(Object key) {
    final String keyf = (String) key;
    Object object;
    object
    = clusterRedisTemplate.execute(new RedisCallback<Object>() {
    public Object doInRedis(RedisConnection connection)
    throws DataAccessException {

             </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] key =<span style="color: rgba(0, 0, 0, 1)"> keyf.getBytes();
             </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] value =<span style="color: rgba(0, 0, 0, 1)"> connection.get(key);
             </span><span style="color: rgba(0, 0, 255, 1)">if</span> (value == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
                 </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
             }
             </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> toObject(value);
    
         }
     });
    
     </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> object;
    

    }

    /**

    • 描述 : <byte[] 转 Object>. <br>
    • <p>
    • < 使用方法说明 >
    • </p>
    • @param bytes
    • @return
      */
      private Object toObject(byte[] bytes) {
      Object obj
      = null;
      try {
      ByteArrayInputStream bis
      = new ByteArrayInputStream(bytes);
      ObjectInputStream ois
      = new ObjectInputStream(bis);
      obj
      = ois.readObject();
      ois.close();
      bis.close();
      }
      catch (IOException ex) {
      ex.printStackTrace();
      }
      catch (ClassNotFoundException ex) {
      ex.printStackTrace();
      }
      return obj;
      }

    private byte[] toByteArray(Object obj) {
    byte[] bytes = null;
    ByteArrayOutputStream bos
    = new ByteArrayOutputStream();
    try {
    ObjectOutputStream oos
    = new ObjectOutputStream(bos);
    oos.writeObject(obj);
    oos.flush();
    bytes
    = bos.toByteArray();
    oos.close();
    bos.close();
    }
    catch (IOException ex) {
    ex.printStackTrace();
    }
    return bytes;
    }
    }

 

最后在 Controller 中调用即可

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
@Controller
@RequestMapping(value = "redisCluster")
public class RedisClusterController {
 
    @Autowired
    private RedisClusterCache redisClusterCache;
 
    @RequestMapping(value = "clusterSave",method = {RequestMethod.GET,RequestMethod.POST})
    @ResponseBody
    public Object clusterSave(){
        //redisClusterCache.put("cluster","save cluster");
        Token token = new Token();
        token.setExpires_in(1000);
        token.setAccess_token("hello world");
        redisClusterCache.put("token",token);
        return "ok";
    }
 
    @RequestMapping(value = "getKey",method = RequestMethod.GET)
    @ResponseBody
    public Object getCluster(String key){
        Object val = redisClusterCache.get(key);
        return val;
    }
} 

注意事项:

  • 版本问题,如果用 spring-data-redis 做集成操作 Reids 集群,只有 spring-data-redis 目前最新版本 1.7 才包含对集群的操作,而最新的 spring-data-redis 中的某些功能对 Spring mvc 的版本也有些限制,所以尽量选择高版本的 Spring mvc 对应。
  • 如果存储的 value 值是一个实体对象,那么一定要实现 Serializable 接