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><dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-oxm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <!-- springframe end --></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<Long><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 > 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<Object><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)"> * 描述 : <byte[]转Object>. <br> * <p> * <使用方法说明> * </p> * * </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<Long><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 > 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 接