Java Spring mvc 操作 Redis 及 Redis 集群
本文内容纲要:
本文原创,转载请注明:http://www.cnblogs.com/fengzheng/p/5941953.html
关于Redis集群搭建可以参考我的另一篇文章Redis集群搭建与简单使用
Redis是什么,能做什么
Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串、哈希表、列表、集合、有序集合,位图,hyperloglogs等数据类型。内置复制、Lua脚本、LRU收回、事务以及不同级别磁盘持久化功能,同时通过RedisSentinel提供高可用,通过RedisCluster提供自动分区。(摘自Redis官网)
作为内存数据库,在现代互联网web系统中,还是主要将Redis作为缓存使用。大型互联网Web系统对性能要求很高,而在前端和数据层之间增加数据缓存已成为必不可少的手段之一,当前比较流行的两个技术就是Redis和Memcached,至于两者有什么区别,不是本文要说的内容。本文主要讲Javaweb如何操作Redis及Redis集群。
一般Java程序操作Redis
Redis提供了多种语言的客户端,在Java中最流行的是Jedis。访问可查看源码及使用方式。目前Jedis最新版本是2.9.0。无论是单机还是集群,Jedis都有很详细的说明和实例代码,这里只做简单说明。如果用Maven做包管理,需要引用jedis包,本例使用最新的2.9.0版本,如下:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
操作Redis单机
importredis.clients.jedis.Jedis;
importredis.clients.jedis.JedisPool;
importredis.clients.jedis.JedisPoolConfig;
/**
*Createdbyfengdezitaion2016/10/9.
*/
publicclassJedisClient{
privatestaticfinalStringhost="192.168.31.121";
privatestaticfinalJedisClientjedisClient=newJedisClient();
privateJedisjedis=null;
/**
*私有构造函数
*/
privateJedisClient(){}
publicstaticJedisClientgetInstance(){
returnjedisClient;
}
privateJedisPoolConfiggetPoolConfig(){
JedisPoolConfigjedisPoolConfig=newJedisPoolConfig();
jedisPoolConfig.setMaxIdle(10);
jedisPoolConfig.setMaxTotal(100);
jedisPoolConfig.setMaxWaitMillis(3000);
returnjedisPoolConfig;
}
/**
*添加
*@paramkey
*@paramvalue
*@return
*@throwsException
*/
publicBooleanadd(Stringkey,Stringvalue)throwsException{
JedisPoolpool=newJedisPool(getPoolConfig(),host);
Jedisjedis=null;
try{
jedis=pool.getResource();
if(jedis.exists(key)){
thrownewException(String.format("key(%s)已存在",key));
}
jedis.set(key,value);
}catch(Exceptione){
throwe;
}
finally{
if(jedis!=null){
jedis.close();
}
}
pool.destroy();
returntrue;
}
/**
*获取值
*@paramkey
*@return
*@throwsException
*/
publicStringget(Stringkey)throwsException{
JedisPoolpool=newJedisPool(getPoolConfig(),host);
Jedisjedis=null;
Stringresult="";
try{
jedis=pool.getResource();
result=jedis.get(key);
}catch(Exceptione){
throwe;
}
finally{
if(jedis!=null){
jedis.close();
}
}
pool.destroy();
returnresult;
}
publicstaticvoidmain(String[]args){
JedisClientjedisClient=JedisClient.getInstance();
try{
/*Booleanresult=jedisClient.add("hello","redis1");
if(result){
System.out.println("success");
}*/
System.out.println(jedisClient.get("hello"));
}catch(Exceptione){
e.printStackTrace();
}
}
}
操作redis集群
importredis.clients.jedis.*;
importjava.util.HashSet;
importjava.util.Set;
/**
*Createdbyfengdezitaion2016/10/13.
*/
publicclassJedisClusterClient{
privatestaticintcount=0;
privatestaticfinalJedisClusterClientredisClusterClient=newJedisClusterClient();
/**
*私有构造函数
*/
privateJedisClusterClient(){}
publicstaticJedisClusterClientgetInstance(){
returnredisClusterClient;
}
privateJedisPoolConfiggetPoolConfig(){
JedisPoolConfigconfig=newJedisPoolConfig();
config.setMaxTotal(1000);
config.setMaxIdle(100);
config.setTestOnBorrow(true);
returnconfig;
}
publicvoidSaveRedisCluster(){
Set<HostAndPort>jedisClusterNodes=newHashSet<HostAndPort>();
jedisClusterNodes.add(newHostAndPort("192.168.31.245",7000));
jedisClusterNodes.add(newHostAndPort("192.168.31.245",7001));
jedisClusterNodes.add(newHostAndPort("192.168.31.245",7002));
jedisClusterNodes.add(newHostAndPort("192.168.31.210",7003));
jedisClusterNodes.add(newHostAndPort("192.168.31.210",7004));
jedisClusterNodes.add(newHostAndPort("192.168.31.210",7005));
JedisClusterjc=newJedisCluster(jedisClusterNodes,getPoolConfig());
jc.set("cluster","thisisarediscluster");
Stringresult=jc.get("cluster");
System.out.println(result);
}
publicstaticvoidmain(String[]args){
JedisClusterClientjedisClusterClient=JedisClusterClient.getInstance();
jedisClusterClient.SaveRedisCluster();
}
}
Springmvc操作Redis
在Springmvc中操作Redis,首先当然要搭好Springmvc框架了。以下是在假设Springmvc环境已经架好的情况下。本例中Spring版本为4.3.2RELEASE。关于Spring的maven引用如下:
<!--spring版本号-->
<spring.version>4.3.2.RELEASE</spring.version>
<!--spring核心包-->
<!--springframestart-->
<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>
<!--springframeend-->
操作Redis单机
只用Jedis自己实现注入(区别于下面的引用spring-data-redis)
把前面的JedisClient代码拿过来引用即可,只需实现一个访问Redis的Service,就可以集成到Springmvc。Service代码如下:
importorg.springframework.stereotype.Service;
importutil.JedisClient;
/**
*Createdbyfengdezitaion2016/10/9.
*/
@Service
publicclassRedisService{
publicStringget(Stringkey)throwsException{
JedisClientjedisClient=JedisClient.getInstance();//上面实现的JedisClient
Stringresult="";
try{
result=jedisClient.get("hello");
}catch(Exceptione){
throwe;
}
returnresult;
}
}
Controller实现如下:
@Controller
@RequestMapping(value="redisAllInOne")
publicclassRedisAllInOneController{
@Autowired
privateRedisServiceredisService;
@RequestMapping(value="get",method=RequestMethod.GET)
@ResponseBody
publicObjectgetByMyService(Stringkey){
try{
Stringresult=redisService.get(key);
returnresult;
}catch(Exceptione){
e.printStackTrace();
}
returnnull;
}
}
用spring-data-redis包做集成
上面是自己实现的注入,这里用spring-data-redis进行集成,只需简单配置即可,需要引用maven包如下,版本为目前最新版1.7.2.RELEASE:
<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服务属性配置文件:
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-redisxml配置文件redis-context.xml:
<!--jedis连接池配置-->
<beanid="poolConfig"class="redis.clients.jedis.JedisPoolConfig">
<propertyname="maxIdle"value="${redis.maxIdle}"/>
<propertyname="maxWaitMillis"value="${redis.maxWait}"/>
<propertyname="testOnBorrow"value="${redis.testOnBorrow}"/>
</bean>
<!--redis服务器中心-->
<beanid="connectionFactory"class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<propertyname="poolConfig"ref="poolConfig"/>
<propertyname="port"value="${redis.port}"/>
<propertyname="hostName"value="${redis.host}"/>
<!--<propertyname="password"value="${redis.password}"/>-->
<propertyname="timeout"value="${redis.timeout}"></property>
<propertyname="database"value="1"></property>
</bean>
<beanid="commonRedisTemplate"class="org.springframework.data.redis.core.RedisTemplate">
<propertyname="connectionFactory"ref="connectionFactory"/>
<propertyname="keySerializer"ref="stringRedisSerializer"/>
<propertyname="hashKeySerializer"ref="stringRedisSerializer"/>
<propertyname="valueSerializer"ref="stringRedisSerializer"/>
<propertyname="hashValueSerializer"ref="stringRedisSerializer"/>
</bean>
<beanid="connectionFactory1"class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<propertyname="poolConfig"ref="poolConfig"/>
<propertyname="port"value="${redis.port}"/>
<propertyname="hostName"value="${redis.host}"/>
<!--<propertyname="password"value="${redis.password}"/>-->
<propertyname="timeout"value="${redis.timeout}"></property>
<propertyname="database"value="2"></property>
</bean>
<beanid="stringRedisSerializer"class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
<beanid="cacheRedisTemplate"class="org.springframework.data.redis.core.RedisTemplate">
<propertyname="connectionFactory"ref="connectionFactory1"/>
<propertyname="keySerializer"ref="stringRedisSerializer"/>
<propertyname="hashKeySerializer"ref="stringRedisSerializer"/>
<propertyname="valueSerializer"ref="stringRedisSerializer"/>
<propertyname="hashValueSerializer"ref="stringRedisSerializer"/>
</bean>
之后在spring配置文件中引用以上文件:
<importresource="redis-context.xml"/>
解释一下上面的配置:
poolConfig即配置redis连接池,之后配置了两个JedisConnectionFactory和RedisTemplate,一个RedisTemplate对应一个JedisConnectionFactory,这样可以配置根据场景配置不同的Redis连接,比如超时时间要求不一致、database0-15可以存储不同的数据等。这里就配置了database1和2,调用commonRedisTemplate会存到database1,调用cacheRedisTemplate会存到database2。
之后在Service层即可注入并引用这两个RedisTemplate,如下代码:
importorg.apache.commons.lang3.StringUtils;
importorg.springframework.dao.DataAccessException;
importorg.springframework.data.redis.connection.RedisConnection;
importorg.springframework.data.redis.core.RedisCallback;
importorg.springframework.data.redis.core.RedisTemplate;
importorg.springframework.stereotype.Repository;
importjavax.annotation.Resource;
importjava.io.*;
@Repository
publicclassRedisCache{
@Resource(name="cacheRedisTemplate")
privateRedisTemplate<String,String>cacheRedisTemplate;
publicvoidput(Objectkey,Objectvalue){
if(null==value){
return;
}
if(valueinstanceofString){
if(StringUtils.isEmpty(value.toString())){
return;
}
}
//TODOAuto-generatedmethodstub
finalStringkeyf=key+"";
finalObjectvaluef=value;
finallongliveTime=86400;
cacheRedisTemplate.execute(newRedisCallback<Long>(){
publicLongdoInRedis(RedisConnectionconnection)
throwsDataAccessException{
byte[]keyb=keyf.getBytes();
byte[]valueb=toByteArray(valuef);
connection.set(keyb,valueb);
if(liveTime>0){
connection.expire(keyb,liveTime);
}
return1L;
}
});
}
publicObjectget(Objectkey){
finalStringkeyf=(String)key;
Objectobject;
object=cacheRedisTemplate.execute(newRedisCallback<Object>(){
publicObjectdoInRedis(RedisConnectionconnection)
throwsDataAccessException{
byte[]key=keyf.getBytes();
byte[]value=connection.get(key);
if(value==null){
returnnull;
}
returntoObject(value);
}
});
returnobject;
}
/**
*描述:<byte[]转Object>.<br>
*<p>
*<使用方法说明>
*</p>
*
*@parambytes
*@return
*/
privateObjecttoObject(byte[]bytes){
Objectobj=null;
try{
ByteArrayInputStreambis=newByteArrayInputStream(bytes);
ObjectInputStreamois=newObjectInputStream(bis);
obj=ois.readObject();
ois.close();
bis.close();
}catch(IOExceptionex){
ex.printStackTrace();
}catch(ClassNotFoundExceptionex){
ex.printStackTrace();
}
returnobj;
}
privatebyte[]toByteArray(Objectobj){
byte[]bytes=null;
ByteArrayOutputStreambos=newByteArrayOutputStream();
try{
ObjectOutputStreamoos=newObjectOutputStream(bos);
oos.writeObject(obj);
oos.flush();
bytes=bos.toByteArray();
oos.close();
bos.close();
}catch(IOExceptionex){
ex.printStackTrace();
}
returnbytes;
}
}
最后在Controller中调用即可
@Autowired
privateRedisCacheredisCache;
@RequestMapping(value="get",method=RequestMethod.GET)
@ResponseBody
publicObjectgetByMyService(Stringkey){
try{
Stringresult=redisService.get(key);
returnresult;
}catch(Exceptione){
e.printStackTrace();
}
returnnull;
}
@RequestMapping(value="save",method=RequestMethod.GET)
@ResponseBody
publicObjectsave(){
Tokentoken=newToken();
token.setAccess_token("token");
token.setExpires_in(1000);
try{
redisCache.put("token",token);
}catch(Exceptione){
e.printStackTrace();
}
return"ok";
}
操作Redis集群
只用Jedis自己实现注入(区别于下面的引用spring-data-redis)
把前面的JedisClusterClient代码拿过来引用即可,只需实现一个访问Redis的Service,就可以集成到Springmvc。Service代码如下:
importorg.springframework.stereotype.Service;
importutil.JedisClusterClient;
/**
*Createdbyfengdezitaion2016/10/13.
*/
@Service
publicclassRedisClusterService{
publicvoidsave()throwsException{
//调用JedisClusterClient中的方法
JedisClusterClientjedisClusterClient=JedisClusterClient.getInstance();
try{
jedisClusterClient.SaveRedisCluster();
}catch(Exceptione){
throwe;
}
}
}
最后在Controller中调用实现的Service即可
@Controller
@RequestMapping(value="redisCluster")
publicclassRedisClusterController{
@Autowired
privateRedisClusterServiceredisClusterService;
@RequestMapping(value="save",method=RequestMethod.GET)
@ResponseBody
publicObjectsave(){
try{
redisClusterService.save();
}catch(Exceptione){
e.printStackTrace();
returnString.format("error:%s",e.getMessage());
}
return"ok";
}
}
用spring-data-redis包做集成
Spring和spring-data-redismaven包引用和前面一致,之所以引用spring-data-redis1.7.2.RELEASE,是因为目前只有这个最新版本才支持集群操作。
redis集群服务属性配置
redis.maxIdle=300
redis.maxWait=3000
redis.testOnBorrow=false
redis.timeout=3000
spring-data-redisxml集群配置文件redis-cluster-context.xml
<!--连接池配置-->
<beanid="poolConfig"class="redis.clients.jedis.JedisPoolConfig">
<propertyname="maxIdle"value="${redis.maxIdle}"/>
<propertyname="maxWaitMillis"value="${redis.maxWait}"/>
<propertyname="testOnBorrow"value="${redis.testOnBorrow}"/>
</bean>
<beanid="redisClusterConfig"class="org.springframework.data.redis.connection.RedisClusterConfiguration">
<propertyname="maxRedirects"value="3"></property>
<propertyname="clusterNodes">
<set>
<beanclass="org.springframework.data.redis.connection.RedisNode">
<constructor-argname="host"value="192.168.31.245"></constructor-arg>
<constructor-argname="port"value="7000"></constructor-arg>
</bean>
<beanclass="org.springframework.data.redis.connection.RedisNode">
<constructor-argname="host"value="192.168.31.245"></constructor-arg>
<constructor-argname="port"value="7001"></constructor-arg>
</bean>
<beanclass="org.springframework.data.redis.connection.RedisNode">
<constructor-argname="host"value="192.168.31.245"></constructor-arg>
<constructor-argname="port"value="7002"></constructor-arg>
</bean>
<beanclass="org.springframework.data.redis.connection.RedisNode">
<constructor-argname="host"value="192.168.31.210"></constructor-arg>
<constructor-argname="port"value="7003"></constructor-arg>
</bean>
<beanclass="org.springframework.data.redis.connection.RedisNode">
<constructor-argname="host"value="192.168.31.210"></constructor-arg>
<constructor-argname="port"value="7004"></constructor-arg>
</bean>
<beanclass="org.springframework.data.redis.connection.RedisNode">
<constructor-argname="host"value="192.168.31.210"></constructor-arg>
<constructor-argname="port"value="7005"></constructor-arg>
</bean>
</set>
</property>
</bean>
<beanid="redis4CacheConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<constructor-argname="clusterConfig"ref="redisClusterConfig"/>
<propertyname="timeout"value="${redis.timeout}"/>
<propertyname="poolConfig"ref="poolConfig"/>
</bean>
<beanname="stringRedisSerializer"class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
<beanid="clusterRedisTemplate"class="org.springframework.data.redis.core.RedisTemplate">
<propertyname="connectionFactory"ref="redis4CacheConnectionFactory"/>
<propertyname="keySerializer"ref="stringRedisSerializer"/>
<propertyname="hashKeySerializer"ref="stringRedisSerializer"/>
<propertyname="valueSerializer"ref="stringRedisSerializer"/>
<propertyname="hashValueSerializer"ref="stringRedisSerializer"/>
</bean>
之后在Spring配置文件中引用
<importresource="redis-cluster-context.xml"/>
解释以上配置:
poolConfig是连接池配置,redisClusterConfig配置了Redis集群的各个节点(节点host和port最好写在属性配置文件中),集群搭建可见我的另一篇博客。然后下面和单机配置一样了,一对JedisConnectionFactory和RedisTemplate。
之后在Service层即可注入并引用这个RedisTemplate,代码如下:
importorg.apache.commons.lang3.StringUtils;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.dao.DataAccessException;
importorg.springframework.data.redis.connection.RedisConnection;
importorg.springframework.data.redis.core.RedisCallback;
importorg.springframework.data.redis.core.RedisTemplate;
importorg.springframework.stereotype.Repository;
importjava.io.*;
/**
*Createdbyfengdezitaion2016/9/29.
*/
@Repository
publicclassRedisClusterCache{
@Autowired
privateRedisTemplateclusterRedisTemplate;
publicvoidput(Objectkey,Objectvalue){
if(null==value){
return;
}
if(valueinstanceofString){
if(StringUtils.isEmpty(value.toString())){
return;
}
}
//TODOAuto-generatedmethodstub
finalStringkeyf=key+"";
finalObjectvaluef=value;
finallongliveTime=86400;
clusterRedisTemplate.execute(newRedisCallback<Long>(){
publicLongdoInRedis(RedisConnectionconnection)
throwsDataAccessException{
byte[]keyb=keyf.getBytes();
byte[]valueb=toByteArray(valuef);
connection.set(keyb,valueb);
if(liveTime>0){
connection.expire(keyb,liveTime);
}
return1L;
}
});
}
publicObjectget(Objectkey){
finalStringkeyf=(String)key;
Objectobject;
object=clusterRedisTemplate.execute(newRedisCallback<Object>(){
publicObjectdoInRedis(RedisConnectionconnection)
throwsDataAccessException{
byte[]key=keyf.getBytes();
byte[]value=connection.get(key);
if(value==null){
returnnull;
}
returntoObject(value);
}
});
returnobject;
}
/**
*描述:<byte[]转Object>.<br>
*<p>
*<使用方法说明>
*</p>
*
*@parambytes
*@return
*/
privateObjecttoObject(byte[]bytes){
Objectobj=null;
try{
ByteArrayInputStreambis=newByteArrayInputStream(bytes);
ObjectInputStreamois=newObjectInputStream(bis);
obj=ois.readObject();
ois.close();
bis.close();
}catch(IOExceptionex){
ex.printStackTrace();
}catch(ClassNotFoundExceptionex){
ex.printStackTrace();
}
returnobj;
}
privatebyte[]toByteArray(Objectobj){
byte[]bytes=null;
ByteArrayOutputStreambos=newByteArrayOutputStream();
try{
ObjectOutputStreamoos=newObjectOutputStream(bos);
oos.writeObject(obj);
oos.flush();
bytes=bos.toByteArray();
oos.close();
bos.close();
}catch(IOExceptionex){
ex.printStackTrace();
}
returnbytes;
}
}
最后在Controller中调用即可
@Controller
@RequestMapping(value="redisCluster")
publicclassRedisClusterController{
@Autowired
privateRedisClusterCacheredisClusterCache;
@RequestMapping(value="clusterSave",method={RequestMethod.GET,RequestMethod.POST})
@ResponseBody
publicObjectclusterSave(){
//redisClusterCache.put("cluster","savecluster");
Tokentoken=newToken();
token.setExpires_in(1000);
token.setAccess_token("helloworld");
redisClusterCache.put("token",token);
return"ok";
}
@RequestMapping(value="getKey",method=RequestMethod.GET)
@ResponseBody
publicObjectgetCluster(Stringkey){
Objectval=redisClusterCache.get(key);
returnval;
}
}
注意事项:
- 版本问题,如果用spring-data-redis做集成操作Reids集群,只有spring-data-redis目前最新版本1.7才包含对集群的操作,而最新的spring-data-redis中的某些功能对Springmvc的版本也有些限制,所以尽量选择高版本的Springmvc对应。
- 如果存储的value值是一个实体对象,那么一定要实现Serializable接口
本文内容总结:
原文链接:https://www.cnblogs.com/fengzheng/p/5941953.html