设为首页 收藏本站
查看: 670|回复: 0

[经验分享] java spring框架中方法级redis的连接自动获取和释放实现

[复制链接]

尚未签到

发表于 2016-12-21 08:28:15 | 显示全部楼层 |阅读模式
java中使用redis总是需要处理redis连接的获取,释放等操作,每次使用都会使代码变的特别丑陋,模仿spring中aop的实现,用动态代理写一个 连接自动获取和释放的工具
主要思路  

JedisManageSupport 抽象类 类似于 aop的切入点,所有继承了该类(一般都是service层)的类,可以使用提供的获取redis的方法获取redis,并且不需要释放

JedisBeanPostProcessor 继承BeanPostProcessor  ,会在bean初始化时执行自己定义的逻辑:

如果A类继承了 JedisManageSupport ,就会获取redis连接并且放到JedisManageSupport 的成员变量里,A类的实例(其实是cglib动态代理生成的

A类的子类的实例)就可以使用该redis连接 进行相关操作了

代理类的实例见源码

源码如下
public class JedisBeanPostProcessor implements BeanPostProcessor {

@Autowired
ShardedJedisPool shardedJedisPool;

static final Logger logger = Logger.getLogger(JedisBeanPostProcessor.class);

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof JedisManageSupport) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(bean.getClass());
enhancer.setCallback(new JedisInterceptor(shardedJedisPool, bean));
Object targetBean = enhancer.create();
return targetBean;
}
else {
return bean;
}
}

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}

class JedisInterceptor implements MethodInterceptor {

static final Logger logger = Logger.getLogger(JedisInterceptor.class);

ShardedJedisPool pool;

Object src;

public JedisInterceptor(ShardedJedisPool pool, Object src) {
this.pool = pool;
this.src = src;
}

@Override
public Object intercept(Object target, Method method, Object[] arguments, MethodProxy methodProxy) throws Throwable {
Object result = null;
if (target instanceof JedisManageSupport) {
if (this.isDeclaredMethod(target, method)) {
ShardedJedis jedis = null;
try {
JedisManageSupport support = (JedisManageSupport) src;
jedis = pool.getResource();
support.setShardedJedis(jedis);
// logger.debug("调用之前注入jedis对象,method:" + method);
/**
* 下面代码可以使用 method.invoke(src,arguments)。 不能使用
* methodProxy.invokeSuper(target,arguments);
* 因为A类中用Autowired注入的属性,生成代理的子类B后,因为子类B是新建的类。从父类继承的属性没有被初始化,
* 使用methodProxy.invokeSuper()执行是,会报空指针异常.
*/
result = methodProxy.invoke(src, arguments);
support.setShardedJedis(null);
}
catch (Exception e) {
pool.returnBrokenResource(jedis);
e.printStackTrace();
}
finally {
if (jedis != null) {
pool.returnResource(jedis);
}
// logger.debug("调用之后归还jedis对象,method:" + method);
}
}
else {
result = methodProxy.invoke(src, arguments);
}
}
else {
throw new Exception("使用该代理必须继承JedisManageSupport");
}
return result;
}

/**
* 是否是target类本身定义的非私有的方法,还是继承的父类
* @return true是target自己类的并且不是私有的的,
*/
private boolean isDeclaredMethod(Object target, Method arg1) {
Method temp = null;
try {
temp = target.getClass().getDeclaredMethod(arg1.getName(), arg1.getParameterTypes());
}
catch (SecurityException e) {
e.printStackTrace();
}
catch (NoSuchMethodException e) {
e.printStackTrace();
}
/**
* 不为null,并且是非私有的,返回true
*/
if (temp != null) {

return true;
}
else {
return false;
}
}
}



public abstract class JedisManageSupport {
ThreadLocal<ShardedJedis> jedisHolder = new ThreadLocal<ShardedJedis>();

public final ShardedJedis getShardedJedis() {
return jedisHolder.get();
}

public final void setShardedJedis(ShardedJedis jedis) {
jedisHolder.set(jedis);
}

/**
* 如果某个键不同单位之间也不会重复,可以使用这个方法生成redis的键
*/
public final byte[] assemKey(String baseKey) {
Assert.isTrue(StringUtils.isNotBlank(baseKey), "参数不能为空");
return baseKey.getBytes();
}

/**
* 根据tableName+prefix 构造唯一key与assemKey(String baseKey, String tableName)
* 规则一致
*/
public final byte[] assemKeyByPrefix(String tableName, String baseKey) {
Assert.isTrue(StringUtils.isNotBlank(baseKey), "参数不能为空");
Assert.isTrue(StringUtils.isNotBlank(tableName), "参数不能为空");
UnitInfo unit = WebService.getUnitInfo();
Assert.isTrue(unit != null, "单位信息获取不到");
return (tableName + "-" + unit.getPrefix() + "-" + baseKey).getBytes();
}

/**
*
* 不同前缀的表中可能有相同的键,同一个表中也可能是有重复的baseKey时,用这个生成redis的key 比如 用户信息表的
* username字段,不同的用户信息表允许重复的username,mooc_t_userinfo
* 也允许有相同的账号,所以生成redis的key时,需要用到单位的mooc_school 放入redis中
*/
public final byte[] assemKeyByFid(String tableName, String baseKey) {
UnitInfo unit = WebService.getUnitInfo();
Assert.isTrue(unit != null, "单位信息获取不到");
return (tableName + "-" + unit.getMoocSchool() + "-" + baseKey).getBytes();
}

}

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-317115-1-1.html 上篇帖子: 分布式架构下的会话追踪实践【基于Cookie和Redis实现】 下篇帖子: Redis-2 数据类型详解之String和key space操作
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表