注:本文参考
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实现事务代理类的思路
本人能力有限,有失误的地方请指正。
时间: 2024-10-27 03:01:02