在springmvc中配置jedis:

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 主要学习https://github.com/thinkgem/jeesite。一下代码均参考于此并稍作修改。 1.jedis 首先,需要添加jedis: redis.clients jedis 2.8.0 2.applicationContext-jedis.xml 然后,springmvc完成基本配置。

主要学习https://github.com/thinkgem/jeesite。一下代码均参考于此并稍作修改。

1.jedis

首先,需要添加jedis:

<!--jedis-->
<dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      <version>2.8.0</version>
</dependency>

2.applicationContext-jedis.xml

然后,springmvc完成基本配置。添加jedispool的bean即可。在spring容器中添加applicationContext-jedis.xml:

在applicationContext-jedis.xml中添加:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.2.xsd">
    <!-- 加载配置属性文件 -->
    <context:property-placeholder ignore-unresolvable="true" location="classpath:db.properties" />

    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="300"/> <!--最大能够保持idel状态的对象数-->
        <property name="maxTotal" value="60000"/><!--最大分配的对象数-->
        <property name="testOnBorrow" value="true"/><!--当调用borrow Oject方法时,是否进行有效性检查-->
    </bean>

    <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
        <constructor-arg index="0" ref="jedisPoolConfig"/>
        <constructor-arg index="1" value="${redis.host}"/>
        <constructor-arg index="2" value="${redis.port}" type="int"/>
        <constructor-arg index="3" value="${redis.timeout}" type="int"/>
        <constructor-arg index="4" value="${redis.auth}"/>
    </bean>
</beans>

注解:参考的源码中的jedisPool配置只有三个参数:config,host,port。我复制后的结果总是getResource失败,因为我的redis添加了auth,所以猜测是不是没通过auth的原因。于是打开JedisPool的源码:

  1 package redis.clients.jedis;
  2 
  3 import java.net.URI;
  4 
  5 import org.apache.commons.pool2.impl.GenericObjectPool;
  6 import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
  7 
  8 import redis.clients.jedis.exceptions.JedisException;
  9 import redis.clients.util.JedisURIHelper;
 10 import redis.clients.util.Pool;
 11 
 12 public class JedisPool extends Pool<Jedis> {
 13 
 14   public JedisPool() {
 15     this(Protocol.DEFAULT_HOST, Protocol.DEFAULT_PORT);
 16   }
 17 
 18   public JedisPool(final GenericObjectPoolConfig poolConfig, final String host) {
 19     this(poolConfig, host, Protocol.DEFAULT_PORT, Protocol.DEFAULT_TIMEOUT, null,
 20         Protocol.DEFAULT_DATABASE, null);
 21   }
 22 
 23   public JedisPool(String host, int port) {
 24     this(new GenericObjectPoolConfig(), host, port, Protocol.DEFAULT_TIMEOUT, null,
 25         Protocol.DEFAULT_DATABASE, null);
 26   }
 27 
 28   public JedisPool(final String host) {
 29     URI uri = URI.create(host);
 30     if (JedisURIHelper.isValid(uri)) {
 31       String h = uri.getHost();
 32       int port = uri.getPort();
 33       String password = JedisURIHelper.getPassword(uri);
 34       int database = JedisURIHelper.getDBIndex(uri);
 35       this.internalPool = new GenericObjectPool<Jedis>(new JedisFactory(h, port,
 36           Protocol.DEFAULT_TIMEOUT, Protocol.DEFAULT_TIMEOUT, password, database, null),
 37           new GenericObjectPoolConfig());
 38     } else {
 39       this.internalPool = new GenericObjectPool<Jedis>(new JedisFactory(host,
 40           Protocol.DEFAULT_PORT, Protocol.DEFAULT_TIMEOUT, Protocol.DEFAULT_TIMEOUT, null,
 41           Protocol.DEFAULT_DATABASE, null), new GenericObjectPoolConfig());
 42     }
 43   }
 44 
 45   public JedisPool(final URI uri) {
 46     this(new GenericObjectPoolConfig(), uri, Protocol.DEFAULT_TIMEOUT);
 47   }
 48 
 49   public JedisPool(final URI uri, final int timeout) {
 50     this(new GenericObjectPoolConfig(), uri, timeout);
 51   }
 52 
 53   public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, int port,
 54       int timeout, final String password) {
 55     this(poolConfig, host, port, timeout, password, Protocol.DEFAULT_DATABASE, null);
 56   }
 57 
 58   public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, final int port) {
 59     this(poolConfig, host, port, Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE, null);
 60   }
 61 
 62   public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, final int port,
 63       final int timeout) {
 64     this(poolConfig, host, port, timeout, null, Protocol.DEFAULT_DATABASE, null);
 65   }
 66 
 67   public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, int port,
 68       int timeout, final String password, final int database) {
 69     this(poolConfig, host, port, timeout, password, database, null);
 70   }
 71 
 72   public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, int port,
 73       int timeout, final String password, final int database, final String clientName) {
 74     this(poolConfig, host, port, timeout, timeout, password, database, clientName);
 75   }
 76 
 77   public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, int port,
 78       final int connectionTimeout, final int soTimeout, final String password, final int database,
 79       final String clientName) {
 80     super(poolConfig, new JedisFactory(host, port, connectionTimeout, soTimeout, password,
 81         database, clientName));
 82   }
 83 
 84   public JedisPool(final GenericObjectPoolConfig poolConfig, final URI uri) {
 85     this(poolConfig, uri, Protocol.DEFAULT_TIMEOUT);
 86   }
 87 
 88   public JedisPool(final GenericObjectPoolConfig poolConfig, final URI uri, final int timeout) {
 89     this(poolConfig, uri, timeout, timeout);
 90   }
 91 
 92   public JedisPool(final GenericObjectPoolConfig poolConfig, final URI uri,
 93       final int connectionTimeout, final int soTimeout) {
 94     super(poolConfig, new JedisFactory(uri, connectionTimeout, soTimeout, null));
 95   }
 96 
 97   @Override
 98   public Jedis getResource() {
 99     Jedis jedis = super.getResource();
100     jedis.setDataSource(this);
101     return jedis;
102   }
103 
104   /**
105    * @deprecated starting from Jedis 3.0 this method will not be exposed.
106    * Resource cleanup should be done using @see {@link redis.clients.jedis.Jedis#close()}
107    */
108   @Override
109   @Deprecated
110   public void returnBrokenResource(final Jedis resource) {
111     if (resource != null) {
112       returnBrokenResourceObject(resource);
113     }
114   }
115 
116   /**
117    * @deprecated starting from Jedis 3.0 this method will not be exposed.
118    * Resource cleanup should be done using @see {@link redis.clients.jedis.Jedis#close()}
119    */
120   @Override
121   @Deprecated
122   public void returnResource(final Jedis resource) {
123     if (resource != null) {
124       try {
125         resource.resetState();
126         returnResourceObject(resource);
127       } catch (Exception e) {
128         returnBrokenResource(resource);
129         throw new JedisException("Could not return the resource to the pool", e);
130       }
131     }
132   }
133 }
View Code

看到有password的参数配置,如果没有配置的话默认为null。到这一步我便没有往下深入看了,因为我连接的redis中有auth,原谅我的不求甚解。于是,我接着配置timeout和auth。timeout直接还是源码的默认值。后面的代码测试通过。在这里我了解到spring的bean注入的几个参数含义:比如property表示属性注入,constructor表示构造函数的参数注入。

 

为了更清楚的表达,redis要设置db,配置文件参数也做一下改动:

<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="300" /> <!-- 最大能够保持idel状态的对象数  -->
        <property name="maxTotal" value="60000" /> <!-- 最大分配的对象数 -->
        <property name="testOnBorrow" value="true" /> <!-- 当调用borrow Object方法时,是否进行有效性检查 -->
    </bean>
    
    <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
        <constructor-arg name="poolConfig" ref="jedisPoolConfig" />
        <constructor-arg name="host" value="${redis.host}" />
        <constructor-arg name="port" value="${redis.port}" type="int" />
        <constructor-arg name="timeout" value="${redis.timeout}" type="int" />
        <constructor-arg name="password" value="#{'${redis.password}'!=''?'${redis.password}':null}" />
        <constructor-arg name="database" value="${redis.db.index}" type="int" />
    </bean>

最后一项参数是选择redis的db,我认为通常默认连接的都是redis的0,那么我们的开发环境为了不冲突,应该另外设置。但JedisPool并没有只有指定db的构造函数,所以选择了这个构造函数。唯一的问题是,默认我们的redis是没有密码的,那么这里也填null而不是空字符串哦。所以,这里使用spring spEL表达式来填充空。对应的配置文件如下:

#redis settings
redis.keyPrefix=wz
redis.host=127.0.0.1
redis.port=6379
redis.timeout=2000
#注意,如果没有password,此处不设置值,但这一项要保留
redis.password=
redis.db.index=1

 

 

3.  JedisUtil

 3.1 getResource

上面设置好了JedisPool,这里就要获取jedis。然后就可以利用jedis进行操作了。

 1  /**
 2      * 获取资源
 3      * @return
 4      */
 5     public static Jedis getResource() {
 6         Jedis jedis = null;
 7         try {
 8             jedis = jedisPool.getResource();
 9             logger.debug("getResource:{}",jedis);
10         } catch (Exception e) {
11             logger.error("getResource:{}",e);
12             if (jedis!=null)
13             jedis.close();
14             throw  e;
15         }
16         return jedis;
17     }

但是,为了更加自定义的设置db,这里也可以加一个db的选择:

    public static Jedis getResource() throws JedisException {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            jedis.select(Integer.parseInt(DB_INDEX));
//            logger.debug("getResource.", jedis);
        } catch (JedisException e) {
            logger.warn("getResource.", e);
            returnBrokenResource(jedis);
            throw e;
        }
        return jedis;
    }

 

 

3.1.1设置prefix

为了我们的key与其他app不冲突,我们最后为我们key统一增加一个标识,这种做法类似选择一个表。

private static String setPrefix(String key) {
    key=KEY_PREFIX+"_"+key;
    return key;
}

在任何使用到redis的地方,配置key的prefix。比如get 和 set:

    public static String get(String key) {
        key = setPrefix(key);
        String value = null;
        Jedis jedis = null;
        try {
            jedis = getResource();
            if (jedis.exists(key)) {
                value = jedis.get(key);
                value = StringUtils.isNotBlank(value) && !"nil".equalsIgnoreCase(value) ? value : null;
                logger.debug("get {} = {}", key, value);
            }
        } catch (Exception e) {
            logger.warn("get {} = {}", key, value, e);
        } finally {
            returnResource(jedis);
        }
        return value;
    }
    public static String set(String key, String value, int cacheSeconds) {
        key = setPrefix(key);
        String result = null;
        Jedis jedis = null;
        try {
            jedis = getResource();
            result = jedis.set(key, value);
            if (cacheSeconds != 0) {
                jedis.expire(key, cacheSeconds);
            }
            logger.debug("set {} = {}", key, value);
        } catch (Exception e) {
            logger.warn("set {} = {}", key, value, e);
        } finally {
            returnResource(jedis);
        }
        return result;
    }

 

 

 

3.2 Object对象的缓存

通过使用jedis基本可以完成任何操作了。这里添加一个缓存对象的功能。java对象的缓存利用序列化实现,因此,需要缓存的对象必须实现了serializable接口。关于如何序列化,参考:将对象序列化和反序列化

 1   /**
 2      * 设置缓存
 3      * @param key String
 4      * @param value Object对象
 5      * @param cacheSeconds 超时时间,0为不超时
 6      * @return
 7      */
 8     public static String setObject(String key,Object value,int cacheSeconds){
 9         String result = null;
10         Jedis jedis = null;
11         try {
12             jedis = getResource();
13             result = jedis.set(getBytesKey(key),toBytes(value));
14             if (cacheSeconds!=0){
15                 jedis.expire(key,cacheSeconds);
16             }
17             logger.debug("setObject {}={}",key,value);
18         } catch (Exception e) {
19             logger.warn("setObject {}  失败:{}",key,e);
20         } finally {
21             jedis.close();
22         }
23         return result;
24     }
25 /**
26      * 获取缓存
27      * @param key
28      * @return 对象(反序列化)
29      */
30     public static Object getObject(String key){
31         Object value = null;
32         Jedis jedis = null;
33         try {
34             jedis = getResource();
35             byte[] bytes = jedis.get(getBytesKey(key));
36             value =  toObject(bytes);
37             logger.debug("getObject {}={}",key,value);
38         } catch (Exception e) {
39             logger.warn("getObject {}错误:{}",key,e.getMessage());
40             e.printStackTrace();
41         } finally {
42             jedis.close();
43         }
44         return value;
45     }
46  /**
47      * 将key转换为byte[]
48      * @param object
49      * @return
50      */
51     private static byte[] getBytesKey(Object object) {
52         if(object instanceof String){
53             return StringUtils.getBytes((String) object);
54         }else {
55             return ObjectUtils.serialize(object);
56         }
57     }
58 
59     /**
60      * Object转换为byte[]类型
61      * @param value Object对象
62      * @return byte[]数组
63      */
64     private static byte[] toBytes(Object value) {
65         return ObjectUtils.serialize(value);
66     }
67 
68     /**
69      * byte[]转换为object
70      * @param bytes
71      * @return
72      */
73     private static Object toObject(byte[] bytes) {
74         return ObjectUtils.unserialize(bytes);
75     }

3.3 ObjectList对象缓存

我们平时用到的list基本都是ObjectList,即list的元素为object而不是String。这样就需要特定方法来缓存了。

采用同样的方式,将object序列化为字节数组,然后存储起来。取出的时候再反序列化,因此object必须实现了serializable接口,而且static的成员不能序列化或者说序列化的结果为默认值。原因参考:将对象序列化和反序列化

  1 /**
  2      * 获取list缓存
  3      * @param key
  4      * @return
  5      */
  6     public static List<String> getList(String key){
  7         key = addDatabaseName(key);
  8         List<String> value = null;
  9         Jedis jedis = null;
 10         try {
 11             jedis = getResource();
 12             value = jedis.lrange(key, 0, -1);
 13             logger.debug("getList {}={}",key,value);
 14         } catch (Exception e) {
 15             logger.warn("getList {}失败:{}",key,e);
 16             e.printStackTrace();
 17         } finally {
 18             jedis.close();
 19         }
 20         return value;
 21     }
 22 
 23     /**
 24      * 获取list缓存,元素是object
 25      * @param key
 26      * @return
 27      */
 28     public static List<Object> getObjectList(String key){
 29         key = addDatabaseName(key);
 30         List<Object> value = null;
 31         Jedis jedis = null;
 32         try {
 33             jedis = getResource();
 34             List<byte[]> list = jedis.lrange(getBytesKey(key), 0, -1);
 35             value = Lists.newArrayList();
 36             for (byte[] bytes : list) {
 37                 value.add(toObject(bytes));
 38             }
 39             logger.debug("getObjectList {}={}",key,value);
 40         }catch (Exception e){
 41             logger.warn("getObjectList {} 失败:{}",key,e);
 42             e.printStackTrace();
 43         }finally {
 44             jedis.close();
 45         }
 46         return value;
 47     }
 48 
 49     /**
 50      * 设置list缓存
 51      * @param key
 52      * @param value
 53      * @param cacheSeconds
 54      * @return
 55      */
 56     public static long setList(String key,List<String> value,int cacheSeconds){
 57         key = addDatabaseName(key);
 58         long result = 0;
 59         Jedis jedis = null;
 60         try {
 61             jedis = getResource();
 62             jedis.del(key);
 63             String[] arr = new String[value.size()];
 64             value.toArray(arr);
 65             result = jedis.rpush(key,arr);
 66             if (cacheSeconds!=0){
 67                 jedis.expire(key,cacheSeconds);
 68             }
 69             logger.debug("setList {}={}",key,value);
 70         }catch (Exception e){
 71             logger.warn("setList {} 错误:",key,e);
 72             e.printStackTrace();
 73         }finally {
 74             jedis.close();
 75         }
 76         return result;
 77     }
 78 
 79     /**
 80      * 设置list缓存,list的元素为object
 81      * @param key
 82      * @param value
 83      * @param cacheSeconds
 84      * @return
 85      */
 86     public static long setObjectList(String key,List<Object> value ,int cacheSeconds){
 87         key = addDatabaseName(key);
 88         long result = 0;
 89         Jedis jedis = null;
 90         try {
 91             jedis = getResource();
 92             jedis.del(key);
 93             ArrayList<byte[]> list = Lists.newArrayList();
 94             for (Object o : value) {
 95                 list.add(toBytes(o));
 96             }
 97             byte[] []arr = new byte[list.size()][];
 98             list.toArray(arr);
 99             result = jedis.rpush(getBytesKey(key),arr);
100             if(cacheSeconds!=0){
101                 jedis.expire(key,cacheSeconds);
102             }
103             logger.debug("setObjectList {}={}",key,value);
104         }catch (Exception e){
105             logger.warn("setObjectList {} 错误:{}",key,e);
106             e.printStackTrace();
107         }
108         return result;
109     }
View Code

 





唯有不断学习方能改变! -- Ryan Miao
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
3月前
|
NoSQL Java 数据库连接
springboot整合Redis中连接池jedis与lettuce的对比和实现
springboot整合Redis中连接池jedis与lettuce的对比和实现
371 0
|
2天前
Springboot-Jedis实现分布式锁
Springboot-Jedis实现分布式锁
6 0
|
1月前
|
NoSQL Redis
springboot2.0整合 RedisTemplate
springboot2.0整合 RedisTemplate
|
6月前
|
Java Redis
springboot2.0整合Jedis
springboot2.0整合Jedis
|
NoSQL Java Redis
SpringBoot高级篇Redis之Jedis配置
SpringBoot2之后,默认采用Lettuce作为redis的连接客户端,当然我们还是可以强制捡回来,使用我们熟悉的Jedis的,本篇简单介绍下使用Jedis的相关配置
1668 0
SpringBoot高级篇Redis之Jedis配置
|
NoSQL Java Redis
SpringBoot中RedisTemplate的RedisScript解析
SpringBoot中RedisTemplate的RedisScript解析
|
存储 缓存 NoSQL
springboot整合spring Cache(redis)
前面有介绍过spring整合redis和redis的一些注意点,在实际开发中,spring cache方便简化的缓存操作的大部分内容。通过注解的方式实现缓存。
789 0
springboot整合spring Cache(redis)
springboot使用RedisTemplate
springboot使用RedisTemplate
255 0
|
存储 JSON NoSQL
Jedis & spring-data-redis
Jedis & spring-data-redis
279 0
|
NoSQL Java Redis
SpringBoot整合Redis_Jedis版(二十)上
一 Jedis 的基本使用 一.一 pom.xml 添加依赖 一.二 Jedis的连接使用 JedisTests 二. SpringBoot 整合 Jedis 使用 二.一 pom.xml 添加依赖 二.二 application.yml 配置Jedis连接信息 二.三 Jedis的连接配置 JedisConfiguration 二.四 测试使用 JedisSpringTests 三. 整合Redis的业务应用 三.一 RedisUtil 工具类
141 0
SpringBoot整合Redis_Jedis版(二十)上