应公司架构原因,没有使用spring,于是就只能自己编一个redis工具类,请大家多多指教。
redisUtils 工具类
package com.bpe.core.db;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bpe.core.util.BPEProperty;
import com.bpe.core.util.ExceptionUtil;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;
/**
* redis 帮助类
*
* @author bpe
*
*/
public class RedisUtil implements Serializable{
private static Logger log = LoggerFactory.getLogger(RedisUtil.class);
private static final long serialVersionUID = -1149678082569464779L;
//可用连接实例的最大数目,默认值为8;
//如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
private static int maxActive = 400;
//控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
private static int maxIdle = 10;
//等待可用连接的最大数目;
private static int maxWait = 1000;
//等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
// private static int timeOut = 6000;
//在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
private static boolean testOnBorrow = false;
public static Jedis jedis;//非切片额客户端连接
public static JedisPool jedisPool;//非切片连接池
public static int count = 0; //初始化jedis连接池数量
{
//静态内部类在类加载时就创建对象,JVM的机制保证了类在加载时是互斥的,所以也是线程安全的
try {
/*log.info("\n----------------------------------------------------------\n\t" +
" RedisUtil initialPool(); \n\t" +
" RedisUtil getJedis(); \n\t" +
" RedisUtil 静态代码块初始化jedis连接池;\n" +
"----------------------------------------------------------");*/
initialPool();
getJedis();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 初始化非切片池
* 单例模式创建连接池且线程安全
*/
static void initialPool()
{
if (jedisPool == null){
synchronized (RedisUtil.class){
if (jedisPool == null){
count ++;
// 池基本配置
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(maxActive);
config.setMaxIdle(maxIdle);
config.setMaxWaitMillis(maxWait);
config.setTestOnBorrow(testOnBorrow);
jedisPool = new JedisPool(config, BPEProperty.JP.dbTyp.redis.host,
Integer.parseInt(BPEProperty.JP.dbTyp.redis.port));
log.info("jedisPool is null 初始化连接池---数量====["+count+"]");
}
}
}
}
//初始化
public static void getJedis() throws Exception {
try {
jedis = new JedisProxy(jedisPool).createProxy();
} catch (Exception e) {
ExceptionUtil.log(log, e);
System.out.println("连接jedisPool失败!");
}
}
public static void closeJedis() throws Exception {
try {
if (jedis != null) {
jedis.close();
}
} catch (Exception e) {
closeBrokenResource(jedis);
System.out.println("close jedisPool error");
}
}
/**
* Return jedis connection to the pool, call different return methods depends on whether the connection is broken
*/
protected static void closeBrokenResource(Jedis jedis) {
try {
System.out.println("closeBrokenResource start");
} catch ( Exception e ) {
destroyJedis(jedis);
}
}
/**
* 在 Jedis Pool 以外强行销毁 Jedis
*/
public static void destroyJedis(Jedis jedis) {
if ( jedis != null ) {
try {
jedis.quit();
} catch (Exception e ) {
System.out.println(">>> RedisUtil-jedis.quit() : " + e );
}
try {
jedis.disconnect();
}catch (Exception e ) {
System.out.println(">>> RedisUtil-jedis.disconnect() : " + e );
}
}
}
/**
* String 新增
* @param key
* @param value
*/
public static void setStr(String key, String value, int expireSecond) {
try {
initialPool();
if (jedis == null) {
getJedis();
}
//jedis.set(key.getBytes(), SerializableUtil.serializable(value));
jedis.set(key, value);
if (expireSecond > 0) {
jedis.expire(key, expireSecond);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* String 删除
* @param key
*/
public void removeStr(String key) {
try {
initialPool();
if (jedis == null) {
getJedis();
}
jedis.del(key);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* String 查询
* @param key
* @return
*/
public static String getStr(String key) {
try {
initialPool();
System.out.println(jedisPool);
if (jedis == null) {
getJedis();
}
/*byte[] bytes = jedis.get(key.getBytes());
String str = null;
if (bytes != null) {
str = String.valueOf(SerializableUtil.unSerializable(bytes));
}*/
String str = jedis.get(key);
return str;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* String 查询
* @param key
* @return
*/
public static Long getTTl(String key) {
Long time = 0L;
initialPool();
if (jedis != null) {
try {
//以秒为单位,返回 key 的剩余生存时间。
time = jedis.ttl(key);
} catch (Exception e) {
e.printStackTrace();
}
}
return time;
}
/**
* list 新增操作
* @param key
* @param value
* vlaue可以是一个string数组,也可以是单个字符串
*/
public static void setList(String key,String...value) {
try {
initialPool();
if (jedis == null) {
getJedis();
}
jedis.lpush(key, value);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* list 删除操作
* @param key
* @param count
* @param value
*/
public static void removeList(String key,int count,String value) {
try {
initialPool();
if (jedis == null) {
getJedis();
}
jedis.lrem(key, count, value);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* list 长度
* @param key
*/
public static Long findListSize(String key) {
try {
initialPool();
Long size = jedis.llen(key);
return size;
} catch (Exception e) {
e.printStackTrace();
log.info("Redis:{}","connect error");
}try {
closeJedis();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 模糊查询所有的key
*/
public static Set findAllKeys(String findName) {
Set keys=null;
try {
// getJedis();
keys = jedis.keys("*"+findName+"*");
} catch (Exception e) {
e.printStackTrace();
log.info("Redis:{}","connect error");
}finally {
try {
closeJedis();
} catch (Exception e) {
e.printStackTrace();
}
}
return keys;
}
/** redis list 增删改查***********************start*/
/**
* 添加一个集合对象
* @param key
* @param value
* value可以是一个string数组,也可以是单个字符串
*
*/
public static void addList(String key, String ...value) {
try {
initialPool();
if (jedis == null) {
getJedis();
}
jedis.lpush(key, value);
} catch (Exception e) {
e.printStackTrace();
log.info("Redis:{}","connect error");
}
}
/**
* 获取list
* @param key
* @param start 开始
* @param end 结束
* @return
* 区间以偏移量 start 和 end 指定。 其中 0 表示列表的第一个元素,
* 1 表示列表的第二个元素,以此类推。 你也可以使用负数下标,以 -1 表示列表的最后一个元素,
* -2 表示列表的倒数第二个元素,以此类推
*/
public static List getList(String key, int start, int end){
List list = null;
try {
initialPool();
if (jedis == null) {
getJedis();
}
//获取指定长度的list集合
list = jedis.lrange(key, start, end);
} catch (Exception e) {
e.printStackTrace();
log.info("Redis:{}","connect error");
}
return list;
}
/**
* 更新List
* @param key
* @param index 索引
* @param value
* 通过索引来设置元素的值
*/
public static void setValue(String key,int index,String value){
try {
initialPool();
if (jedis == null) {
getJedis();
}
//获取指定长度的list集合
jedis.lset(key, index, value);
} catch (Exception e) {
e.printStackTrace();
log.info("Redis:{}","connect error");
}
}
/**
* 删除List
* @param key
* @param count
* @param value
* count > 0 : 从表头开始向表尾搜索,移除与 VALUE 相等的元素,数量为 COUNT 。
* count < 0 : 从表尾开始向表头搜索,移除与 VALUE 相等的元素,数量为 COUNT 的绝对值。
* count = 0 : 移除表中所有与 VALUE 相等的值。
*/
public static void removeValue(String key,int count,String value){
try {
initialPool();
if (jedis == null) {
getJedis();
}
jedis.lrem(key, count, value);
} catch (Exception e) {
e.printStackTrace();
log.info("Redis:{}","connect error");
}
}
}
JedisHandler
package com.bpe.core.db;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.InvocationHandler;
import com.bpe.core.util.BPEProperty;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class JedisHandler implements InvocationHandler {
private JedisPool jedisPool;
public JedisHandler(JedisPool jedisPool){
this.jedisPool = jedisPool;
}
/**
* 当使用jedis方法的时候,实际调用的这里的方法
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Jedis jedis = null;
try {
if (jedisPool == null) {
RedisUtil.initialPool();
System.out.println("RedisUtil jedisPool is null 再次初始化连接池");
}
jedis = jedisPool.getResource();
if(!"127.0.0.1".equals(BPEProperty.JP.dbTyp.redis.host)) {
jedis.auth(BPEProperty.JP.dbTyp.redis.pwd);
}else {
jedis.auth(BPEProperty.JP.dbTyp.redis.pwd);
}
Object invoke = method.invoke(jedis, args);
return invoke;
}finally {
//开始关闭redis资源
if (jedis != null) {
jedis.close();
}
}
}
}
JedisProxy
package com.bpe.core.db;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Enhancer;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
/**
* spring cglib 动态代理关闭redis资源
* @author bpe
*/
public class JedisProxy {
private JedisPool jedisPool;
public JedisProxy(JedisPool jedisPool) {
this.jedisPool = jedisPool;
}
public Jedis createProxy() throws Exception{
Enhancer enhancer = new Enhancer();
//设置代理的父类,就设置需要代理的类
enhancer.setSuperclass(Jedis.class);
//设置自定义的代理方法
Callback callback = new JedisHandler(jedisPool);
enhancer.setCallback(callback);
Object o = enhancer.create();
Jedis jedis = null;
if (o instanceof Jedis){
jedis = (Jedis) o;
}
return jedis;
}
}
java使用redis一般都是通过redis.clients.jedis.Jedis来连接redis服务器,通过redis.clients.jedis.Jedis提供的方法使用redis
但是每次执行完jedis里面的方法之后必须关闭链接,释放资源,否则链接一旦用完下次再使用redis程序会堵塞,但是手动关闭链接或出现很多的重复代码,并且有些时候也会忘记关闭
解决方法就是使用代理模式来解决这一问题
代理有两种:java的Proxy类和Spring的Enhancer
区别就是前者只能代理基于接口的类,也就是说代理的类必须是接口,否则无法代理
后者是Spring的代理类,弥补java的Proxy只能代理接口的缺陷
Enhancer使用非常简单,只要使用了Spring就会有,全类目是org.springframework.cglib.proxy.Enhancer
以后获取Jedis对象通过new JedisProxy().createProxy(),使用jedis的方法都会自动关闭连接了
————————————————
后面还是有一部分东西不全,比如对于连接池满了该如何做,是阻塞还是其他等等。
在这里博主就不深究了