码迷,mamicode.com
首页 > 其他好文 > 详细

cglib实现jfinal service上添加事务 多数据源切换改进

时间:2015-05-13 20:02:45      阅读:213      评论:0      收藏:0      [点我收藏+]

标签:

注:本文参考

http://www.oschina.net/code/snippet_188964_26555

http://my.oschina.net/jally/blog/180366

实现进行改进。


一、思路

想在service层开事务,想到的是代理service的方法,在代理中开启事务,然后执行被代理方法,最后提交事务。

二、实现

cglib的MethodInterceptor可以代理对象的所有方法,使用非常方便,所以这里使用cglib来代理service对象。

为了表明那个方法需要开启事务,这里新建一个注解MethodTx,用来表示要开启事务。

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface MethodTx {
	public abstract String config() default (String) "main";
}

注解中的config用来指定使用的数据源,默认使用主数据源,在jfinal中主数据源默认命名为main。

下面是实现代理类:

public class TxProxy implements MethodInterceptor {

	private static final Logger log = LoggerFactory.getLogger(TxProxy.class);

	/**
	 * 事务包装
	 * 
	 * @author shizc
	 *
	 */
	private class TxInvoke implements IAtom {
		private Object target = null;
		private MethodProxy proxy = null;
		private Object[] args = null;
		private Object result = null;
		private String dsConfig = null;

		@SuppressWarnings("unused")
		private TxInvoke() {

		}

		public TxInvoke(Object target, MethodProxy proxy, Object[] args) {
			super();
			this.target = target;
			this.proxy = proxy;
			this.args = args;
		}

		public boolean run() throws SQLException {
			boolean flag = false;
			try {
				result = proxy.invokeSuper(target, args);
				flag = true;
			} catch (Throwable e) {
				log.error("调用事务失败", e);
			}
			return flag;
		}

		public Object getResult() {
			return result;
		}

	}

	public Object intercept(Object obj, Method method, Object[] args,
			MethodProxy proxy) throws Throwable {

		Object result = null;
		if (method.isAnnotationPresent(MethodTx.class)) {
			MethodTx methodTx = method.getAnnotation(MethodTx.class);
			String conf = methodTx.config();
			// 包装成事务
			TxInvoke invoke = new TxInvoke(obj, proxy, args);
			log.debug("开始事务--------->{}", conf);
			if (StringUtils.isNotBlank(conf) && !"main".equalsIgnoreCase(conf)) {
				Db.use(conf).tx(invoke);
			} else {
				Db.tx(invoke);
			}
			log.debug("结束事务--------->{}", conf);
			result = invoke.getResult();
		} else {
			// 没有事务,直接执行
			result = proxy.invokeSuper(obj, args);
		}

		return result;
	}

}

核心思路就是在实现intercept方法中,判断被代理的方法是否有MethodTx注解。如果有MethodTx注解,则选择对应的数据源开启事务执行。如果没有则执行原始方法。

最后,为了得到被代理对象,需要一个工厂类来生成被代理的代理对象:

/**
 * service代理工厂
 * @author shizc
 *
 */
public class TxProxyFactory {
	private static final Logger log = LoggerFactory.getLogger(TxProxyFactory.class);

	/**
	 * 获取要代理的对象
	 * 
	 * @param targetClass
	 *            被代理的对象
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T newProxy(Class<T> targetClass) {

		if (targetClass == null) {
			return null;
		}
		Object proxy = null;
		Enhancer en = new Enhancer();
		en.setSuperclass(targetClass);
		// 代理回调
		en.setCallback(new TxProxy());
		proxy = en.create();
		log.debug("创建代理类:{}", targetClass.getName());

		return (T) proxy;
	}
}

使用方法:

public class TestService {
	public static final TestService me = TxProxyFactory.newProxy(TestService.class);
	}

三、总结

关键是cglib的使用结合Db.Tx来生成代理类。其中切换数据源使用的也是Db.use方法。jfinal使用起来确实比较简单方便。最后感谢 @JFinal 开源这么优秀的框架 感谢@泡泡队长 @hyanqing 提供cglib实现事务代理类的思路

本人能力有限,有失误的地方请指正。

cglib实现jfinal service上添加事务 多数据源切换改进

标签:

原文地址:http://my.oschina.net/purely/blog/414483

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!