在springmvc中配置jedis:
主要学习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的源码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
看到有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的成员不能序列化或者说序列化的结果为默认值。原因参考:将对象序列化和反序列化。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
关注我的公众号
![](https://images2018.cnblogs.com/blog/686418/201808/686418-20180822091328437-1109977663.jpg)