jFinal事务实现的原理

作者: 海纳百川_spark | 来源:发表于2016-05-24 19:06 被阅读4201次

本文内容

  1. jFinal怎样使用数据库事务
  2. jFinal的事务是怎么实现的
  1. 在需要事务的方法上添加注解@Before(Tx.class),代码如下
@Before(Tx.class)
public boolean updateOrder(Order order){
  .......
}

并且在实例化此类的时候实用动态代理来增强,代码如下

private OrderDao orderDao = Enhancer.enhance(OrderDao.class);
  1. 从Enhancer类的enhance方法开始,enhance方法的代码如下
public static <T> T enhance(Class<T> targetClass) {
    return (T)net.sf.cglib.proxy.Enhancer.create(targetClass, new Callback());
}

使用cglib的动态代理功能来增强目标类,通过回调Callback类中的intercept方法来调用被代理类的方法,intercept代码如下

public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        if (excludedMethodName.contains(method.getName())) {
            if (method.getName().equals("finalize"))
                return methodProxy.invokeSuper(target, args);
            return this.injectTarget != null ? methodProxy.invoke(this.injectTarget, args) : methodProxy.invokeSuper(target, args);
        }
        
        if (this.injectTarget != null) {
            target = this.injectTarget;
            Interceptor[] finalInters = InterceptorBuilder.build(injectInters, target.getClass(), method);
            Invocation invocation = new Invocation(target, method, args, methodProxy, finalInters);
            invocation.useInjectTarget = true;
            invocation.invoke();
            return invocation.getReturnValue();
        }
        else {
            Interceptor[] finalInters = InterceptorBuilder.build(injectInters, target.getClass(), method);
            Invocation invocation = new Invocation(target, method, args, methodProxy, finalInters);
            invocation.useInjectTarget = false;
            invocation.invoke();
            return invocation.getReturnValue();
        }
    }

首先判断方法名为“finalize”的逻辑不看,跳过
看下面if中的代码

if (this.injectTarget != null) {
    target = this.injectTarget;
    // 获取到所有的拦截器集合
    Interceptor[] finalInters = InterceptorBuilder.build(injectInters, target.getClass(), method);
    // 将拦截器交给Invocation
    Invocation invocation = new Invocation(target, method, args, methodProxy, finalInters);
    invocation.useInjectTarget = true;
    // 然后调用
    invocation.invoke();
    return invocation.getReturnValue();
}

第一步获取到所有的拦截器集合,InterceptorBuilder.build的代码如下

public static Interceptor[] build(Interceptor[] injectInters, Class<?> targetClass, Method method) {
        Interceptor[] methodInters = createInterceptors(method.getAnnotation(Before.class));
        
        // no Clear annotation
        Clear clear = method.getAnnotation(Clear.class);
        if (clear == null) {
            Interceptor[] classInters = createInterceptors(targetClass.getAnnotation(Before.class));
            Interceptor[] result = new Interceptor[globalInters.length + injectInters.length + classInters.length + methodInters.length];
            int index = 0;
            for (Interceptor inter : globalInters)
                result[index++] = inter;
            for (Interceptor inter : injectInters)
                result[index++] = inter;
            for (Interceptor inter : classInters)
                result[index++] = inter;
            for (Interceptor inter : methodInters)
                result[index++] = inter;
            return result;
        }
        
        // Clear annotation without parameter
        Class<? extends Interceptor>[] clearInters = clear.value();
        if (clearInters.length == 0)
            return methodInters;
        
        // Clear annotation with parameter
        Interceptor[] classInters = createInterceptors(targetClass.getAnnotation(Before.class));
        Interceptor[] temp = new Interceptor[globalInters.length + injectInters.length + classInters.length];
        int index = 0;
        for (Interceptor inter : globalInters)
            temp[index++] = inter;
        for (Interceptor inter : injectInters)
            temp[index++] = inter;
        for (Interceptor inter : classInters)
            temp[index++] = inter;
        
        int removeCount = 0;
        for (int i=0; i<temp.length; i++) {
            for (Class<? extends Interceptor> ci : clearInters) {
                if (temp[i].getClass() == ci) {
                    temp[i] = null;
                    removeCount++;
                    break;
                }
            }
        }       
        
        Interceptor[] result = new Interceptor[temp.length + methodInters.length - removeCount];
        index = 0;
        for (Interceptor inter : temp)
            if (inter != null)
                result[index++] = inter;
        for (Interceptor inter : methodInters)
            result[index++] = inter;
        return result;
    }

第二步将拦截器交给Invocation
第三步调用invocation.invoke(),看invoke的代码

public void invoke() {
    // 递归调用拦截器
    if (index < inters.length) {
        // 将拦截器实例传入一下拦截器
        inters[index++].intercept(this);
    }
    else if (index++ == inters.length) {    // index++ ensure invoke action only one time
        try {
            // Invoke the action
            if (action != null) {
                // 调用到具体Controller子类的方法
                returnValue = action.getMethod().invoke(target, args);
            }
            // Invoke the method
            else {
                if (useInjectTarget){
                    returnValue = methodProxy.invoke(target, args);
                }
                else{
                    returnValue = methodProxy.invokeSuper(target, args);
                }
            }
        }
        catch (InvocationTargetException e) {
            Throwable t = e.getTargetException();
            throw t instanceof RuntimeException ? (RuntimeException)t : new RuntimeException(e);
        }
        catch (RuntimeException e) {
            throw e;
        }
        catch (Throwable t) {
            throw new RuntimeException(t);
        }
    }
}

递归调用拦截器,并把自己的实例传入进去。
最终会调用到Tx类中的intercept方法,因为Tx类就是一个拦截器,代码如下

public void intercept(Invocation inv) {
    Config config = getConfigWithTxConfig(inv);
    if (config == null)
        config = DbKit.getConfig();
    
    Connection conn = config.getThreadLocalConnection();
    if (conn != null) { // Nested transaction support
        try {
            if (conn.getTransactionIsolation() < getTransactionLevel(config))
                conn.setTransactionIsolation(getTransactionLevel(config));
            inv.invoke();
            return ;
        } catch (SQLException e) {
            throw new ActiveRecordException(e);
        }
    }
    
    Boolean autoCommit = null;
    try {
        conn = config.getConnection();
        autoCommit = conn.getAutoCommit();
        config.setThreadLocalConnection(conn);
        conn.setTransactionIsolation(getTransactionLevel(config));  // conn.setTransactionIsolation(transactionLevel);
        conn.setAutoCommit(false);
        inv.invoke();
        conn.commit();
    } catch (NestedTransactionHelpException e) {
        if (conn != null) try {conn.rollback();} catch (Exception e1) {e1.printStackTrace();}
    } catch (Throwable t) {
        if (conn != null) try {conn.rollback();} catch (Exception e1) {e1.printStackTrace();}
        throw t instanceof RuntimeException ? (RuntimeException)t : new ActiveRecordException(t);
    }
    finally {
        try {
            if (conn != null) {
                if (autoCommit != null)
                    conn.setAutoCommit(autoCommit);
                conn.close();
            }
        } catch (Throwable t) {
            t.printStackTrace();    // can not throw exception here, otherwise the more important exception in previous catch block can not be thrown
        }
        finally {
            config.removeThreadLocalConnection();   // prevent memory leak
        }
    }
}

1)从config中获取连接对象conn,保留连接事务的开关
2)把conn连接对象交给本地线程保管,确保下游数据库操作获取的conn对象是同一个 3)配置事务级别
4)设置手动提交事务
5)inv.invoke();这一行代码会调用下一个拦截器,最终调用到上面invoke() 方法内的这几行代码,因为useInjectTarget是false,所以看else中的代码

if (useInjectTarget){
    returnValue = methodProxy.invoke(target, args);
}
else{
    returnValue = methodProxy.invokeSuper(target, args);
}

这就执行了开头介绍的方法,

@Before(Tx.class)
public boolean updateOrder(Order order){
  .......
}

方法内的数据库操作完成后,继续执行conn.commit();提交事务
6)如果有事务异常就回滚
7)还原连接的事务开关
8)从本地线程中移除连接
这就完成了事务操作

相关文章

  • jFinal事务实现的原理

    本文内容 jFinal怎样使用数据库事务jFinal的事务是怎么实现的 在需要事务的方法上添加注解@Before(...

  • JFinal实现原理

    刚接触Jfinal,后面继续整理; Jfinal源码解析http://blog.csdn.net/soul_cod...

  • JFinal的Proxy实现原理

    了解Java的动态代理后,动态创建新的代理类通过反射执行。 那JFinal的代理实现有什么不一样的地方呢,据作者介...

  • Spring事务完全解析

    事务是什么?了解事务的原理吗?说下Spring的事务原理,能自己实现Spring事务原理吗?先自我检测下这些知识掌...

  • Spring事物原理完全解析

    事务是什么?了解事务的原理吗?说下Spring的事务原理,能自己实现Spring事务原理吗?先自我检测下这些知识掌...

  • redis事务以及watch的理解

    事务的特性 实现的机制 WATCH 原理 [参考自redis设计与实现:第19章 事务]

  • Redis 事务操作原理

    事务原理剖析 redis事务操作,原理是基于pipe队列实现原子性提交操作,在只想事务操作,相当于将需要提交的命令...

  • mysql事务隔离机制及其隔离级别、实现原理分析

    目录 事务特性ACID属性 并发事务带来的问题 事务隔离级别 事务实现原理 事务特性ACID属性 事务特性指的就是...

  • mysql事务隔离机制及其原理

    目录 事务特性ACID属性 并发事务带来的问题 事务隔离级别 事务实现原理 闲聊 【迈莫coding】 事务特性A...

  • java消息队列ActiveMQ的简单使用

    activeMQ 是学习java消息队列的实现项目,使用jfinal +jfinal-ext + activeMQ...

网友评论

    本文标题:jFinal事务实现的原理

    本文链接:https://www.haomeiwen.com/subject/ksvzrttx.html