1.spring-data-redis与Jedis简单整合
spring-data-redis与Jedis简单整合,Redis没有任何集群只是单节点工做,使用链接池
1.建立spring-context-jedis.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" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd" default-lazy-init="false"> <!-- 链接池配置. --> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <!-- 链接池中最大链接数。高版本:maxTotal,低版本:maxActive --> <property name="maxTotal" value="8" /> <!-- 链接池中最大空闲的链接数. --> <property name="maxIdle" value="4" /> <!-- 链接池中最少空闲的链接数. --> <property name="minIdle" value="1" /> <!-- 当链接池资源耗尽时,调用者最大阻塞的时间,超时将跑出异常。单位,毫秒数;默认为-1.表示永不超时。高版本:maxWaitMillis,低版本:maxWait --> <property name="maxWaitMillis" value="5000" /> <!-- 链接空闲的最小时间,达到此值后空闲链接将可能会被移除。负值(-1)表示不移除. --> <property name="minEvictableIdleTimeMillis" value="300000" /> <!-- 对于“空闲连接”检测线程而言,每次检测的连接资源的个数。默认为3 --> <property name="numTestsPerEvictionRun" value="3" /> <!-- “空闲连接”检测线程,检测的周期,毫秒数。若是为负值,表示不运行“检测线程”。默认为-1. --> <property name="timeBetweenEvictionRunsMillis" value="60000" /> <!-- testOnBorrow:向调用者输出“连接”资源时,是否检测是有有效,若是无效则从链接池中移除,并尝试获取继续获取。默认为false。建议保持默认值. --> <!-- testOnReturn:向链接池“归还”连接时,是否检测“连接”对象的有效性。默认为false。建议保持默认值.--> <!-- testWhileIdle:向调用者输出“连接”对象时,是否检测它的空闲超时;默认为false。若是“连接”空闲超时,将会被移除。建议保持默认值. --> <!-- whenExhaustedAction:当“链接池”中active数量达到阀值时,即“连接”资源耗尽时,链接池须要采起的手段, 默认为1(0:抛出异常。1:阻塞,直到有可用连接资源。2:强制建立新的连接资源) --> </bean> <!-- Spring提供的Redis链接工厂 --> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy"> <!-- 链接池配置. --> <property name="poolConfig" ref="jedisPoolConfig" /> <!-- Redis服务主机. --> <property name="hostName" value="192.168.110.101" /> <!-- Redis服务端口号. --> <property name="port" value="6379" /> <!-- Redis服务链接密码. --> <!-- <property name="password" value="${redis.password}" /> --> <!-- 连超时设置. --> <property name="timeout" value="15000" /> <!-- 是否使用链接池. --> <property name="usePool" value="true" /> </bean> <!-- Spring提供的访问Redis类. --> <bean id="jedisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory" /> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <property name="valueSerializer"> <!-- <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /> --> <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" /> </property> </bean></beans>
2.使用Spring提供的RedisTemplate类
public static void main(String[] args){ ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-context-jedis.xml"); // 获取Spring提供的RedisTemplate类此类封装了Jedis,简化操做 RedisTemplate<String, List<String>> redisTemplate = applicationContext.getBean("jedisTemplate", RedisTemplate.class); // Spring 提供的各类Redis结构的key-value操做类 ValueOperations<String, List<String>> value = redisTemplate.opsForValue(); HashOperations<String, Object, Object> hash = redisTemplate.opsForHash(); ListOperations<String, List<String>> list = redisTemplate.opsForList(); HyperLogLogOperations<String, List<String>> hyperLogLog = redisTemplate.opsForHyperLogLog(); SetOperations<String, List<String>> set = redisTemplate.opsForSet(); ZSetOperations<String, List<String>> zSet = redisTemplate.opsForZSet(); List<String> listValue = new ArrayList<String>(); listValue.add("001"); listValue.add("002"); value.set("list", listValue); System.out.println(value.get("list")); // 关闭Spring容器释放资源 applicationContext.close();}
3.关于RedisTemplate类源码学习
RedisTemplate类的属性
private boolean enableTransactionSupport = false;private boolean exposeConnection = false;private boolean initialized = false;private boolean enableDefaultSerializer = true;// 默认的序列化实现private RedisSerializer<?> defaultSerializer = new JdkSerializationRedisSerializer();// 各类操做的序列化方式定义private RedisSerializer keySerializer = null;private RedisSerializer valueSerializer = null;private RedisSerializer hashKeySerializer = null;private RedisSerializer hashValueSerializer = null;private RedisSerializer<String> stringSerializer = new StringRedisSerializer();private ScriptExecutor<K> scriptExecutor;// Spring 提供的各类Redis结构的key-value操做类// cache singleton objects (where possible)private ValueOperations<K, V> valueOps;private ListOperations<K, V> listOps;private SetOperations<K, V> setOps;private ZSetOperations<K, V> zSetOps;private HyperLogLogOperations<K, V> hllOps;
在一个应用中RedisTemplate类对象能够是单例的,由于其属性“ valueOps、listOps、setOps、zSetOps、hllOps
”的各类操做也是线程安全的,源码以下:
获取其
“
valueOps
、
listOps
、
setOps
、
zSetOps
、
hllOps
”
属性:
public ValueOperations<K, V> opsForValue(){ if (valueOps == null) { valueOps = new DefaultValueOperations<K, V>(this); } return valueOps;}public ListOperations<K, V> opsForList(){ if (listOps == null) { listOps = new DefaultListOperations<K, V>(this); } return listOps;}// 省略部分......
其属性“
valueOps
、
listOps
、
setOps
、
zSetOps
、
hllOps
”的各类操做也是线程安全的,例如
valueOps
属性对象默认实现类
DefaultValueOperations
<
K
,
V
>
源码:
public void set(K key, V value){ final byte[] rawValue = rawValue(value); execute(new ValueDeserializingRedisCallback(key) { protected byte[] inRedis(byte[] rawKey, RedisConnection connection) { connection.set(rawKey, rawValue); return null; } }, true);}// 省略其余操做......
再看看
execute
的实现以下:
//org.springframework.data.redis.core.AbstractOperations<K, V><T> T execute(RedisCallback<T> callback, boolean b) { return template.execute(callback, b);}// template.execute实现以下:// org.springframework.data.redis.core.RedisTemplate<K, V>public <T> T execute(RedisCallback<T> action, boolean exposeConnection) { return execute(action, exposeConnection, false);}// execute实现以下:// org.springframework.data.redis.core.RedisTemplate<K, V> --- 最终实现public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) { Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it"); Assert.notNull(action, "Callback object must not be null"); RedisConnectionFactory factory = getConnectionFactory(); RedisConnection conn = null; try { if (enableTransactionSupport) { // only bind resources in case of potential transaction synchronization conn = RedisConnectionUtils.bindConnection(factory, enableTransactionSupport); } else { conn = RedisConnectionUtils.getConnection(factory); } boolean existingConnection = TransactionSynchronizationManager.hasResource(factory); RedisConnection connToUse = preProcessConnection(conn, existingConnection); boolean pipelineStatus = connToUse.isPipelined(); if (pipeline && !pipelineStatus) { connToUse.openPipeline(); } RedisConnection connToExpose = (exposeConnection ? connToUse : createRedisConnectionProxy(connToUse)); T result = action.doInRedis(connToExpose); // close pipeline if (pipeline && !pipelineStatus) { connToUse.closePipeline(); } // TODO: any other connection processing? return postProcessResult(result, connToUse, existingConnection); } finally { if (!enableTransactionSupport) { RedisConnectionUtils.releaseConnection(conn, factory); } }}
此时已经能够看出每次操做都会建立一个新的
RedisConnection
对象使用完成会调用
RedisConnectionUtils
.
releaseConnection
(
conn
,
factory
)
方法释放链接,若想查看其建立
RedisConnection
链接和
RedisConnectionUtils
.
releaseConnection
(
conn
,
factory
)
释放链接过程可继续查看其源码,此处就不赘述了。
2.JedisConnectionFactory中使用sentinel集群
1.在
spring-context-jedis.xml
中配置sentinel信息
<!-- Redis sentinel集群配置 --><bean id="sentinelConfig" class="org.springframework.data.redis.connection.RedisSentinelConfiguration"> <constructor-arg index="0" type="java.lang.String" value="master001" /> <constructor-arg index="1" type="java.util.Set"> <set> <value>192.168.110.100:26379</value> <value>192.168.110.100:36379</value> <value>192.168.110.100:46379</value> </set> </constructor-arg></bean><!-- Spring提供的Redis链接工厂 --><bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy"> <!-- Redis sentinel集群配置 --> <constructor-arg index="0" type="org.springframework.data.redis.connection.RedisSentinelConfiguration" ref="sentinelConfig" /> <!-- 链接池配置. --> <constructor-arg index="1" type="redis.clients.jedis.JedisPoolConfig" ref="jedisPoolConfig" /> <!-- Redis服务主机. --> <property name="hostName" value="192.168.110.101" /> <!-- Redis服务端口号. --> <property name="port" value="6379" /> <!-- Redis服务链接密码. --> <!-- <property name="password" value="${redis.password}" /> --> <!-- 连超时设置. --> <property name="timeout" value="15000" /> <!-- 是否使用链接池. --> <property name="usePool" value="true" /></bean>
2.使用测试代码
public static void main(String[] args){ ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-context-jedis.xml"); // 获取Spring提供的RedisTemplate类此类封装了Jedis,简化操做 RedisTemplate<String, String> redisTemplate = applicationContext.getBean("jedisTemplate", RedisTemplate.class); ValueOperations<String, String> value = redisTemplate.opsForValue(); value.set("K001", "V001"); System.out.println(value.get("K001")); // 关闭Redis Master服务 Scanner scanner = new Scanner(System.in); String input = scanner.nextLine(); System.out.println(input); value.set("K002", "V002"); System.out.println(value.get("K002")); // 关闭Spring容器释放资源 applicationContext.close();}
代码输出,注意中间的打印:
2015-10-3 15:10:59 redis.clients.jedis.JedisSentinelPool initSentinels信息: Trying to find master from available Sentinels...2015-10-3 15:10:59 redis.clients.jedis.JedisSentinelPool initSentinels信息: Redis master running at 192.168.110.101:6379, starting Sentinel listeners...2015-10-3 15:10:59 redis.clients.jedis.JedisSentinelPool initPool信息: Created JedisPool to master at 192.168.110.101:6379V0012015-10-3 15:11:38 redis.clients.jedis.JedisSentinelPool initPool信息: Created JedisPool to master at 192.168.110.103:6379V002
3.JedisConnectionFactory中使用JedisShardInfo
Spring-Data-Redis好像并不支持Redis分片集群,可是JedisConnectionFactory源码中有一个JedisShardInfo属性,源码以下:
- private JedisShardInfo shardInfo;
// 省略......public void afterPropertiesSet() { if (shardInfo == null) { shardInfo = new JedisShardInfo(hostName, port); if (StringUtils.hasLength(password)) { shardInfo.setPassword(password); } if (timeout > 0) { setTimeoutOn(shardInfo, timeout); } } if (usePool) { this.pool = createPool(); }}// 省略......protected Jedis fetchJedisConnector() { try { if (usePool && pool != null) { return pool.getResource(); } Jedis jedis = new Jedis(getShardInfo()); // force initialization (see Jedis issue #82) jedis.connect(); return jedis; } catch (Exception ex) { throw new RedisConnectionFailureException("Cannot get Jedis connection", ex); }}
-------------------------------------------------------------------------------------------------------------------------------