Skip to content

spring data redis集成jodis的简单实现

Yrlix Joe edited this page Mar 22, 2018 · 4 revisions

项目要使用spring-data-redis的抽象实现,又要通过jodis实现codisproxy的负载和热备,看到前面issue有提示,就花时间研究了一下。

如果要使用RedisTemplate的话,它在jedis上抽象了一层JedisConnection,需要把pool放进去,RedisTemplate释放连接使用RedisConnectionUtils.releaseConnection(conn, factory);这个方法最后使用JedisConnection的close(如果有pool就return连接,如果没有就直接quit+disconnect关闭连接),而不是调用Jedis.close(它会判断Datasource即pool是否为空,有则return连接,没有就close掉)。虽然jodis拿到的jedis里带了pool信息,但是取不出来放到JecisConnection,RedisTemplate使用RedisConnectionUtils.releaseConnection 释放连接时,就直接close掉jedis连接而无法return给pool。

解决方法是:RoundRobinJedisPool.getResource时直接返回JedisConnection.

1. 在RoundRobinJedisPool加返回JedisConnection的方法:

@Override
public JedisConnection getResourceForSpringDataRedis() {
    ImmutableList<PooledObject> pools = this.pools;
      if (pools.isEmpty()) {
          throw new JedisException("Proxy list empty");
      }
      for (;;) {
          int current = nextIdx.get();
          int next = current >= pools.size() - 1 ? 0 : current + 1;
          if (nextIdx.compareAndSet(current, next)) {      
            Pool<Jedis> pool=pools.get(next).pool;
            return new JedisConnection(pool.getResource(),pool,0);
          }
      }
    
}

2. 实现ConnectionFactory

public class JodisConnectionFactory implements InitializingBean, DisposableBean, RedisConnectionFactory {
	private final static Log log = LogFactory.getLog(JodisConnectionFactory.class);
	private static final ExceptionTranslationStrategy EXCEPTION_TRANSLATION = new PassThroughExceptionTranslationStrategy(
			JedisConverters.exceptionConverter());	
	JedisResourcePool jodisPool;	
	public JodisConnectionFactory(JedisResourcePool jodisPool) {
		this.jodisPool=jodisPool;
	}
	@Override
	public RedisConnection getConnection() {		
		return jodisPool.getResourceForSpringDataRedis();
	}
	@Override
	public void destroy() throws Exception {
		if(jodisPool != null)
			jodisPool.close();
	}
	@Override
	public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
		return EXCEPTION_TRANSLATION.translate(ex);
	}	
	@Override
	public RedisClusterConnection getClusterConnection() {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public boolean getConvertPipelineAndTxResults() {
		// TODO Auto-generated method stub
		return false;
	}
	@Override
	public RedisSentinelConnection getSentinelConnection() {
		// TODO Auto-generated method stub
		return null;
	}	
	@Override
	public void afterPropertiesSet() throws Exception {
		// TODO Auto-generated method stub
	}
}

3. 在@configuration类里加注解初始化对应的类

@Bean
public JedisResourcePool jodisPool() {
  JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
  jedisPoolConfig.setMaxTotal(20);
  jedisPoolConfig.setMaxIdle(20);
  jedisPoolConfig.setMinIdle(5);
  jedisPoolConfig.setMaxWaitMillis(-1);
  return RoundRobinJedisPool.create().curatorClient("192.168.11.62:2181", 30000).zkProxyDir("/jodis/codis-demo").build();
}
@Bean
public JodisConnectionFactory redisConnectionFactory(){
  return new JodisConnectionFactory(jodisPool());
}	
@Bean
public RedisTemplate<Object, Object> redisTemplate(
    RedisConnectionFactory redisConnectionFactory)
        throws UnknownHostException {
  RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
  template.setConnectionFactory(redisConnectionFactory());
  return template;
}
  1. @Autowired注入RedisTemplate就能使用了
Clone this wiki locally