<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:task="http://www.springframework.org/schema/task" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 其中order属性代表其加载顺序, 而ignoreUnresolvablePlaceholders为是否忽略不可解析的 Placeholder, 如配置了多个PropertyPlaceholderConfigurer,则需设置为true 其中classpath是引用src目录下的文件写法。 --> <bean id="propertyConfigurerRedis" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="order" value="1" /> <property name="ignoreUnresolvablePlaceholders" value="true" /> <property name="locations"> <list> <value>classpath:redis.properties</value> </list> </property> </bean> <!-- 单个redis配置 --> <!-- redis连接池的配置 --> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxIdle" value="${redis.maxIdle}"/> <property name="minIdle" value="${redis.minIdle}"/> <property name="testOnBorrow" value="${redis.testOnBorrow}"/> <property name="testOnReturn" value="${redis.testOnReturn}"/> </bean> <!-- redis的连接池pool,不是必选项:timeout/password --> <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"/> <!-- port--> <constructor-arg index="3" value="${redis.timeout}" type="int"/> <!-- timeout --> <constructor-arg index="4" value="${redis.password}"/> <!-- password --> </bean> <!-- 以下是spring-data-redis配置方式 --> <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.password}" p:pool-config-ref="jedisPoolConfig"/> <!-- SDR默认采用的序列化策略有两种,一种是String的序列化策略,一种是JDK的序列化策略。 StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。 RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。 就是因为序列化策略的不同,即使是同一个key用不同的Template去序列化,结果是不同的。所以根据key去删除数据的时候就出现了删除失败的问题。 --> <!-- redis 序列化策略 ,通常情况下key值采用String序列化策略, --> <!-- 如果不指定序列化策略,StringRedisTemplate的key和value都将采用String序列化策略; --> <!-- 但是RedisTemplate的key和value都将采用JDK序列化 这样就会出现采用不同template保存的数据不能用同一个template删除的问题 --> <bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer" /> <bean id="redisTemplate" 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"/> </bean> <!-- redis jedisCluster集群配置 --> <!-- <bean name="genericObjectPoolConfig" class="org.apache.commons.pool2.impl.GenericObjectPoolConfig" > <property name="maxWaitMillis" value="-1" /> <property name="maxTotal" value="1000" /> <property name="minIdle" value="8" /> <property name="maxIdle" value="100" /> </bean> <bean id="jedisCluster" class="cn.zsmy.palmdoctor.redis.JedisClusterFactory"> <property name="addressConfig"> <value>classpath:redis.properties</value> </property> <property name="addressKeyPrefix" value="address" /> 属性文件里 key的前缀 <property name="password" value="123456" /> redis密码 <property name="timeout" value="300000" /> <property name="maxRedirections" value="6" /> <property name="genericObjectPoolConfig" ref="genericObjectPoolConfig" /> </bean> --> </beans>
spring-context-jedis-cluster.xml
<?xml version="1.0" encoding="UTF-8"?> <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"> <description>Jedis Cluster Configuration集群</description> <!-- 加载配置属性文件 按需加载 --> <context:property-placeholder ignore-unresolvable="true" location="classpath:redis-cluster.properties" /> <bean id="redisClusterConfiguration" class="org.springframework.data.redis.connection.RedisClusterConfiguration"> <property name="maxRedirects" value="${redis.maxRedirects}"></property> <property name="clusterNodes"> <set> <bean class="org.springframework.data.redis.connection.RedisClusterNode"> <constructor-arg name="host" value="${redis.host1}"></constructor-arg> <constructor-arg name="port" value="${redis.port1}"></constructor-arg> </bean> <bean class="org.springframework.data.redis.connection.RedisClusterNode"> <constructor-arg name="host" value="${redis.host2}"></constructor-arg> <constructor-arg name="port" value="${redis.port2}"></constructor-arg> </bean> <bean class="org.springframework.data.redis.connection.RedisClusterNode"> <constructor-arg name="host" value="${redis.host3}"></constructor-arg> <constructor-arg name="port" value="${redis.port3}"></constructor-arg> </bean> <bean class="org.springframework.data.redis.connection.RedisClusterNode"> <constructor-arg name="host" value="${redis.host4}"></constructor-arg> <constructor-arg name="port" value="${redis.port4}"></constructor-arg> </bean> <bean class="org.springframework.data.redis.connection.RedisClusterNode"> <constructor-arg name="host" value="${redis.host5}"></constructor-arg> <constructor-arg name="port" value="${redis.port5}"></constructor-arg> </bean> <bean class="org.springframework.data.redis.connection.RedisClusterNode"> <constructor-arg name="host" value="${redis.host6}"></constructor-arg> <constructor-arg name="port" value="${redis.port6}"></constructor-arg> </bean> </set> </property> </bean> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxIdle" value="${redis.maxIdle}" /> <property name="maxTotal" value="${redis.maxTotal}" /> </bean> <bean id="jeidsConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" > <constructor-arg ref="redisClusterConfiguration" /> <constructor-arg ref="jedisPoolConfig" /> </bean> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="jeidsConnectionFactory" /> </bean> </beans>
redis-cluster.properties
#cluster configuration
redis.host1=xx.xx.xx.xx
redis.port1=7000
redis.host2=xx.xx.xx.xx
redis.port2=7001
redis.host3=xx.xx.xx.xx
redis.port3=7002
redis.host4=xx.xx.xx.xx
redis.port4=7000
redis.host5=xx.xx.xx.xx
redis.port5=7001
redis.host6=xx.xx.xx.xx
redis.port6=7002
redis.maxRedirects=3
redis.maxIdle=100
redis.maxTotal=600
package cn.zsmy.palmdoctor.redis; import java.io.Serializable; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.core.BoundSetOperations; import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.ListOperations; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; @Service public class RedisUtil { @Autowired @Qualifier("redisTemplate") public RedisTemplate<String, Object> redisTemplate; @Autowired @Qualifier("redisTemplate") protected RedisTemplate<Serializable, Serializable> redisTemplateSerializable; /** * 缓存基本的对象,Integer、String、实体类等 * @param key 缓存的键值 * @param value 缓存的值 * @return 缓存的对象 */ public void setCacheObject(String key, Object value) { redisTemplate.opsForValue().set(key,value); } /** * 获得缓存的基本对象。 * @param key 缓存键值 * @param operation * @return 缓存键值对应的数据 */ public Object getCacheObject(String key/*,ValueOperations<String,T> operation*/) { return redisTemplate.opsForValue().get(key); } /** * 缓存List数据 * @param key 缓存的键值 * @param dataList 待缓存的List数据 * @return 缓存的对象 */ public Object setCacheList(String key, List<Object> dataList) { ListOperations<String, Object> listOperation = redisTemplate.opsForList(); if(null != dataList) { int size = dataList.size(); for(int i = 0; i < size ; i ++) { listOperation.rightPush(key,dataList.get(i)); } } return listOperation; } /** * 获得缓存的list对象 * @param key 缓存的键值 * @return 缓存键值对应的数据 */ public List<Object> getCacheList(String key) { List<Object> dataList = new ArrayList<Object>(); ListOperations<String, Object> listOperation = redisTemplate.opsForList(); Long size = listOperation.size(key); for(int i = 0 ; i < size ; i ++) { dataList.add(listOperation.leftPop(key)); } return dataList; } /** * 获得缓存的list对象 * @Title: range * @Description: TODO(这里用一句话描述这个方法的作用) * @param @param key * @param @param start * @param @param end * @param @return * @return List<T> 返回类型 * @throws */ public List<Object> range(String key, long start, long end) { ListOperations<String, Object> listOperation = redisTemplate.opsForList(); return listOperation.range(key, start, end); } /** * list集合长度 * @param key * @return */ public Long listSize(String key) { return redisTemplate.opsForList().size(key); } /** * 覆盖操作,将覆盖List中指定位置的值 * @param key * @param int index 位置 * @param String * value 值 * @return 状态码 * */ public void listSet(String key, int index, Object obj) { redisTemplate.opsForList().set(key, index, obj); } /** * 向List尾部追加记录 * * @param String * key * @param String * value * @return 记录总数 * */ public long leftPush(String key, Object obj) { return redisTemplate.opsForList().leftPush(key, obj); } /** * 向List头部追加记录 * * @param String * key * @param String * value * @return 记录总数 * */ public long rightPush(String key, Object obj) { return redisTemplate.opsForList().rightPush(key, obj); } /** * 算是删除吧,只保留start与end之间的记录 * * @param String * key * @param int start 记录的开始位置(0表示第一条记录) * @param int end 记录的结束位置(如果为-1则表示最后一个,-2,-3以此类推) * @return 执行状态码 * */ public void trim(String key, int start, int end) { redisTemplate.opsForList().trim(key, start, end); } /** * 删除List中c条记录,被删除的记录值为value * * @param String * key * @param int c 要删除的数量,如果为负数则从List的尾部检查并删除符合的记录 * @param Object * obj 要匹配的值 * @return 删除后的List中的记录数 * */ public long remove(String key, long i, Object obj) { return redisTemplate.opsForList().remove(key, i, obj); } /** * 缓存Set * @param key 缓存键值 * @param dataSet 缓存的数据 * @return 缓存数据的对象 */ public BoundSetOperations<String, Object> setCacheSet(String key,Set<Object> dataSet) { BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key); /*T[] t = (T[]) dataSet.toArray(); setOperation.add(t);*/ Iterator<Object> it = dataSet.iterator(); while(it.hasNext()) { setOperation.add(it.next()); } return setOperation; } /** * 获得缓存的set * @param key * @param operation * @return */ public Set<Object> getCacheSet(String key/*,BoundSetOperations<String,T> operation*/) { Set<Object> dataSet = new HashSet<Object>(); BoundSetOperations<String,Object> operation = redisTemplate.boundSetOps(key); Long size = operation.size(); for(int i = 0 ; i < size ; i++) { dataSet.add(operation.pop()); } return dataSet; } /** * 缓存Map * @param key * @param dataMap * @return */ public int setCacheMap(String key,Map<String, Object> dataMap) { if(null != dataMap) { HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash(); for (Map.Entry<String, Object> entry : dataMap.entrySet()) { /*System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue()); */ if(hashOperations != null){ hashOperations.put(key,entry.getKey(),entry.getValue()); } else{ return 0; } } } else{ return 0; } return dataMap.size(); } /** * 获得缓存的Map * @param key * @param hashOperation * @return */ public Map<Object, Object> getCacheMap(String key/*,HashOperations<String,String,T> hashOperation*/) { Map<Object, Object> map = redisTemplate.opsForHash().entries(key); /*Map<String, T> map = hashOperation.entries(key);*/ return map; } /** * 缓存Map * @param key * @param dataMap * @return */ public void setCacheIntegerMap(String key,Map<Integer, Object> dataMap) { HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash(); if(null != dataMap) { for (Map.Entry<Integer, Object> entry : dataMap.entrySet()) { /*System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue()); */ hashOperations.put(key,entry.getKey(),entry.getValue()); } } } /** * 获得缓存的Map * @param key * @param hashOperation * @return */ public Map<Object, Object> getCacheIntegerMap(String key/*,HashOperations<String,String,T> hashOperation*/) { Map<Object, Object> map = redisTemplate.opsForHash().entries(key); /*Map<String, T> map = hashOperation.entries(key);*/ return map; } /** * 从hash中删除指定的存储 * * @param String * @return 状态码,1成功,0失败 * */ public long deleteMap(String key) { redisTemplate.setEnableTransactionSupport(true); return redisTemplate.opsForHash().delete(key); } /** * 设置过期时间 * @param key * @param time * @param unit * @return */ public boolean expire(String key, long time, TimeUnit unit) { return redisTemplate.expire(key, time, unit); } /** * increment * @param key * @param step * @return */ public long increment(String key, long step) { return redisTemplate.opsForValue().increment(key, step); } //redisTemplateSerializable /** * 删除redis的所有数据 */ /*@SuppressWarnings({"unchecked", "rawtypes"}) public String flushDB() { return redisTemplateSerializable.execute(new RedisCallback() { public String doInRedis(RedisConnection connection) throws DataAccessException { connection.flushDb(); return "ok"; } }); }*/ public long del(final byte[] key) { return (long) redisTemplateSerializable.execute(new RedisCallback<Object>() { public Long doInRedis(RedisConnection connection) { return connection.del(key); } }); } @SuppressWarnings({"unchecked", "rawtypes"}) public byte[] get(final byte[] key) { return (byte[]) redisTemplateSerializable.execute(new RedisCallback() { public byte[] doInRedis(RedisConnection connection) throws DataAccessException { return connection.get(key); } }); } /** * @param key * @param value * @param liveTime */ public void set(final byte[] key, final byte[] value, final long liveTime) { redisTemplateSerializable.execute(new RedisCallback<Object>() { public Long doInRedis(RedisConnection connection) throws DataAccessException { connection.set(key, value); if (liveTime > 0) { connection.expire(key, liveTime); } return 1L; } }); } }
package cn.zsmy.palmdoctor.redis; import java.util.HashSet; import java.util.Properties; import java.util.Set; import java.util.regex.Pattern; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.io.Resource; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster; public class JedisClusterFactory implements FactoryBean<JedisCluster>, InitializingBean { private Resource addressConfig; private String addressKeyPrefix ; private String password; private JedisCluster jedisCluster; private Integer timeout; private Integer maxRedirections; private GenericObjectPoolConfig genericObjectPoolConfig; private Pattern p = Pattern.compile("^.+[:]\d{1,5}\s*$"); @Override public JedisCluster getObject() throws Exception { return jedisCluster; } @Override public Class<? extends JedisCluster> getObjectType() { return (this.jedisCluster != null ? this.jedisCluster.getClass() : JedisCluster.class); } @Override public boolean isSingleton() { return true; } private Set<HostAndPort> parseHostAndPort() throws Exception { try { Properties prop = new Properties(); prop.load(this.addressConfig.getInputStream()); Set<HostAndPort> haps = new HashSet<HostAndPort>(); for (Object key : prop.keySet()) { if (!((String) key).startsWith(addressKeyPrefix)) { continue; } String val = (String) prop.get(key); boolean isIpPort = p.matcher(val).matches(); if (!isIpPort) { throw new IllegalArgumentException("ip 或 port 不合法"); } String[] ipAndPort = val.split(":"); HostAndPort hap = new HostAndPort(ipAndPort[0], Integer.parseInt(ipAndPort[1])); haps.add(hap); } return haps; } catch (IllegalArgumentException ex) { throw ex; } catch (Exception ex) { throw new Exception("解析 jedis 配置文件失败", ex); } } @Override public void afterPropertiesSet() throws Exception { Set<HostAndPort> haps = this.parseHostAndPort(); //jedisCluster = new JedisCluster(haps, timeout, maxRedirections,genericObjectPoolConfig); jedisCluster = new JedisCluster(haps, timeout, 2000, maxRedirections, password, genericObjectPoolConfig); } public void setAddressConfig(Resource addressConfig) { this.addressConfig = addressConfig; } public void setTimeout(int timeout) { this.timeout = timeout; } public void setMaxRedirections(int maxRedirections) { this.maxRedirections = maxRedirections; } public void setAddressKeyPrefix(String addressKeyPrefix) { this.addressKeyPrefix = addressKeyPrefix; } public void setGenericObjectPoolConfig(GenericObjectPoolConfig genericObjectPoolConfig) { this.genericObjectPoolConfig = genericObjectPoolConfig; } public void setPassword(String password) { this.password = password; } }
package cn.zsmy.palmdoctor.redis; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import cn.zsmy.constant.Constant; /** * @author shm */ public class SerializeUtil { public static byte[] serialize(Object value) { if (value == null) { throw new NullPointerException("Can't serialize null"); } byte[] rv = null; ByteArrayOutputStream bos = null; ObjectOutputStream os = null; try { bos = new ByteArrayOutputStream(); os = new ObjectOutputStream(bos); os.writeObject(value); os.close(); bos.close(); rv = bos.toByteArray(); } catch (Exception e) { e.printStackTrace(); Constant.MY_LOG.info("serialize error"); } finally { close(os); close(bos); } return rv; } public static Object deserialize(byte[] in) { return deserialize(in, Object.class); } @SuppressWarnings("unchecked") public static <T> T deserialize(byte[] in, Class<T> requiredType) { Object rv = null; ByteArrayInputStream bis = null; ObjectInputStream is = null; try { if (in != null) { bis = new ByteArrayInputStream(in); is = new ObjectInputStream(bis); rv = is.readObject(); } } catch (Exception e) { e.printStackTrace(); Constant.MY_LOG.info("deserialize error"); } finally { close(is); close(bis); } return (T) rv; } private static void close(Closeable closeable) { if (closeable != null) try { closeable.close(); } catch (IOException e) { e.printStackTrace(); Constant.MY_LOG.info("close stream error"); } } }