本文主要就spring注入的连接池使用问题,做简要说明。
使用过JedisPool的同学会发现,通过JedisPool获取资源,在使用完毕后,需要显式的将资源放回连接池中,
如下:
JedisPool jedisPool;
Jedis jedis = jedisPool.getResource();
//操作
jedisPool.returnResource(jedis);
如果未显示的回收资源,则在连接池中资源使用完毕后,系统会出现阻塞。
因为如果使用连接池,就相当于将客户端连接托管给池,而池中资源又是事先设定,及有限资源,
那么在资源都被占用,且无人回收时,就会出现一直阻塞等待资源。
但是在每个操作后都显示的调用资源回收,又显得代码臃肿,此处建议考虑通过动态代理实现,及在每次操作前
通过代理获取资源,操作后再将资源回收。代码设计如下:
public class RedisService implements IMemCached {
/**
* 连接池
*/
@Getter
@Setter
private JedisPool jedisPool;
@Getter
@Setter
private Jedis jedis;
/**
*
* @Title: initJedis
* @Description: 从连接池获取连接
*/
public void initJedis(){
this.jedis = jedisPool.getResource();
}
/**
*
* @Title: returnJedis
* @Description: 将连接放回连接池
*/
public void returnJedis(){
jedisPool.returnResource(jedis);
}
@Override
public boolean setValue(String key, Object value)
throws MemcachedOpException {
return OK.equals(jedis.set(key,
null == value ? StringUtils.EMPTY : value.toString()));
}
@Override
public boolean setValue(String key, Object value, int expTime)
throws MemcachedOpException {
return OK.equals(jedis.setex(key,expTime,
null == value ? StringUtils.EMPTY : value.toString()));
}
@Override
public Object getValue(String key) throws MemcachedOpException {
return jedis.get(key);
}
@Override
public Object getValue(String key, long timeout)
throws MemcachedOpException {
return getValue(key);
}
public List<String> getValue(String... keys) throws MemcachedOpException {
return jedis.mget(keys);
}
/**
*
* @Title: sadd
* @Description: 添加一个或者多个元素到集合(set)里
* @param key
* @param members
* @return
*/
public boolean sadd(final String key,String... members) throws MemcachedOpException{
return 1==jedis.sadd(key, members);
}
/**
*
* @Title: sRandomMember
* @Description: 从集合里面随机获取一个值
* @param key
* @return
*/
public String sRandomMember(final String key) throws MemcachedOpException{
return jedis.srandmember(key);
}
@Override
public IMemCached getProxy() {
return new ProxyHandler().bind(this);
}
@Override
public void flush() throws MemcachedFlushException {
jedis.flushDB();
}
}
/**
* 动态代理类 用于解决jedis需手工放回连接池的问题
* @author guozb
*
*/
class ProxyHandler implements InvocationHandler{
private RedisService redis;
/**
*
* @Title: bind
* @Description: 绑定代理对象
* @param imem
* @return
*/
public IMemCached bind(RedisService imem){
this.redis = (RedisService) imem;
return (IMemCached)Proxy.newProxyInstance(RedisService.class.getClassLoader(), RedisService.class.getInterfaces(), this);
}
@Override
public Object invoke(Object arg0, Method arg1, Object[] arg2)
throws Throwable {
//从连接池获取资源
redis.initJedis();
Object obj = arg1.invoke(redis, arg2);
//将资源放回连接池
redis.returnJedis();
return obj;
}
}
这样在使用时,通过调用getProxy()进行具体操作即可。