jFinal事务实现的原理

本文内容

  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 enhance(Class 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[] 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 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事务实现的原理)