spring源码学习之事务的创建过程

上文中讲到authUserServiceImpl的代理类通过ObjenesisCglibAopProxy的方式创建出来,这篇文章继续分析,代理类的目标方法在调用之前,事务的创建过程,同样使用前文中提到的测试例子。

public class AuthUserServiceImplTest {
    private static Logger logger = Logger.getLogger(AuthUserServiceImplTest.class);

    public static void main(String[] args){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
        IAuthUserService authUserServiceImpl = ctx.getBean(AuthUserServiceImpl.class);
        int ret = authUserServiceImpl.delete("user002");
    }
}

从下面的截图中可以看得出来,authUserServiceImpl这个变量实际引用的是内存中的“AuthUserServiceImpl$EnhancerBySpringCGLIB$ea1acdac@3108”对象,这是cglib通过字节码增加的方式,创建出来的代理对象,只存在于内存中。通过断点调试可以看出来,代理类中存在一系列的拦截器,

执行authUserServiceImpl.delete("user002")方法,通过调试执行下一步之后,就会进入到CglibAopProxy$DynamicAdvisedInterceptor这个拦截器的intercept()方法,其他的拦截器打了断点,貌似都没有执行,至于什么时候执行,不是本文关注的重点,忽略。

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            try {
                target = this.getTarget();
                if (target != null) {
                    targetClass = target.getClass();
                }
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                Object retVal;
                retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();
            }
            return retVal;
        }

这个intercept方法中得到了一个chain列表,列表中存放的就是两个拦截器,一个是ExposeInvocationInterceptor,另外一个就是TransactionInterceptor,

这两个拦截器是从哪儿来的呢?

从代码可以看得出来是和这个advised变量有关,这个变量引用的就是一个ProxyFactory,从上文记录,创建代理之前,首先创建了一个ProxyFactory,这段代码在AbstractAutoProxyCreator.createProxy()方法中。下面省略了部分代码。

protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
        ProxyFactory proxyFactory = new ProxyFactory();
        Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);
        Advisor[] var7 = advisors;
        int var8 = advisors.length;

        for(int var9 = 0; var9 < var8; ++var9) {
            Advisor advisor = var7[var9];
            proxyFactory.addAdvisor(advisor);
        }
        return proxyFactory.getProxy(this.getProxyClassLoader());
    }

从这一行proxyFactory.addAdvisor(advisor)就可以看出,在创建代理工厂的时候,直接放了两个advisor配置器,一个是ExposeInvocationInterceptor的成员变量public static final Advisor ADVISOR,这是一个默认的配置器,不是我们分析的重点,忽略,以下省略部分代码,

public class ExposeInvocationInterceptor implements MethodInterceptor, PriorityOrdered, Serializable {
    public static final Advisor ADVISOR;
    
    static {
        ADVISOR = new DefaultPointcutAdvisor(INSTANCE) {
            public String toString() {
                return ExposeInvocationInterceptor.class.getName() + ".ADVISOR";
            }
        };
        invocation = new NamedThreadLocal("Current AOP method invocation");
    }
}


另外一个是DefaultBeanFactoryPointcutAdvisor,<aop:advisor>标签对应的classbean对象是DefaultBeanFactoryPointcutAdvisor,从上面的类图可以看出,他们都是Advisor的实现类,这两个advisor又是从哪儿来的呢?

框架在初始化目标bean的时候,会调用处理器AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization()方法,这个过程中,处理器会从beanFactory工厂中取出所有的Advisor的实现类,并将其存储在上面我们看到的Object[] specificInterceptors变量中。

这两个Advisor的内部会有一个Advice的成员变量,DefaultPointcutAdvisor的advice是ExposeInvocationInterceptor,从上面的类图中可以看出ExposeInvocationInterceptor既是一个MethodInterceptor拦截器,也是一个advice,DefaultBeanFactoryPointcutAdvisor的advice是TransactionInterceptor,从上面的类图中可以看出TransactionInterceptor既是一个MethodInterceptor拦截器,也是一个advice。

回到上面的问题,List<Object> chain中这两个拦截器是从哪儿来的呢?就是从这两个Advisor中获取出来的。

CglibAopProxy$DynamicAdvisedInterceptor这个拦截器的intercept()方法中拿到这两个拦截器之后,就会调用CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed()方法,看看proceed()方法具体内容:

public Object proceed() throws Throwable {
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return this.invokeJoinpoint();
        } else {
            Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
            if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
                InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
                return dm.methodMatcher.matches(this.method, this.targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();
            } else {
                return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
            }
        }
    }

这个变量中interceptorsAndDynamicMethodMatchers存放的就是上面提到的两个拦截器,这个方法的作用就是顺序调用两个拦截器的invoke()方法。代码中并没有使用for循环来遍历interceptorsAndDynamicMethodMatchers这个集合,那是怎么做到顺序调用所有的拦截器的呢?

因为在调用拦截器的invoke(this)方法的时候,传入了this,也就是传入了CglibAopProxy$CglibMethodInvocation的实例,这样其他的拦截器中就会有获取到这个CglibMethodInvocation的引用,比如看看ExposeInvocationInterceptor这个拦截器中的invoke方法:

public Object invoke(MethodInvocation mi) throws Throwable {
        MethodInvocation oldInvocation = (MethodInvocation)invocation.get();
        invocation.set(mi);
        Object var3;
        try {
            var3 = mi.proceed();
        } finally {
            invocation.set(oldInvocation);
        }
        return var3;
    }

从mi.proceed();这行就可以看得出来,使用mi这个变量,又调用回CglibMethodInvocation的proceed()方法。回到proceed()方法之后,this.currentInterceptorIndex已经被++,这样就可以取到列表中下一个拦截器,进而执行下一个拦截器的invoke()方法。

ExposeInvocationInterceptor拦截器做了什么事情不是关注的重点,忽略,我们重点分析TransactionInterceptor这个拦截器中的内容。

TransactionInterceptor拦截器的invoke()方法调用了invokeWithinTransaction()方法,同时创建了一个匿名类,这个匿名类的方法中又执行了invocation.proceed(),执行完invokeWithinTransaction()方法之后,程序就会回到CglibAopProxy.CglibMethodInvocation.proceed()方法。

	public Object invoke(final MethodInvocation invocation) throws Throwable {
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

		return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
			@Override
			public Object proceedWithInvocation() throws Throwable {
				return invocation.proceed();
			}
		});
	}

在TransactionInterceptor拦截器中invokeWithinTransaction()方法中,定义了整个事物控制的流程。

	protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
			throws Throwable {
		final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
		final String joinpointIdentification = methodIdentification(method, targetClass);

		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
            //开启事物
			TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
			Object retVal = null;
			try {
                //执行目标方法
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
                //执行目标方法异常回滚
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}finally {
				cleanupTransactionInfo(txInfo);
			}
            //提交事物
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}
	}

事物控制的流程大致分为3 步,第一步开启事物,第二步执行目标方法,第三部,提交事务,如果出现异常情况,进入异常分支处理异常。首先看看事物的创建过程。

开启事物

开启事物的过程中,会创建几个关键的和事物相关的对象,DataSourceTransactionManager、DataSourceTransactionObject、DefaultTransactionStatus、TransactionInfo、RuleBasedTransactionAttribute等

创建事物属性RuleBasedTransactionAttribute

事物拦截器TransactionInterceptor有一个私有变量TransactionAttributeSource transactionAttributeSource,它的实现类是NameMatchTransactionAttributeSource,它是<tx:attributes>标签对应的classbean对象。根据bean.xml中的配置:

        <tx:attributes>
            <tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>
            <tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
            <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
            <tx:method name="save*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>
            <tx:method name="remove*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>
            <tx:method name="add*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>
            <tx:method name="select*" propagation="SUPPORTS"/>
            <tx:method name="query*" propagation="SUPPORTS"/>
        </tx:attributes>

spring会将tx:method标签解析成为一个RuleBasedTransactionAttribute对象,并将其存储在transactionAttributeSource中的一个私有的成员变量,private Map<String, TransactionAttribute> nameMap = new HashMap<String, TransactionAttribute>()。

按照当前的例子,我们调用的目标方法是authUserServiceImpl.delete("user002"),所以根据方法的名字delete,就可以从nameMap中获取到一个TransactionAttribute,这个TransactionAttribute中记录了事物的传播特性、事物的隔离级别、事物的异常回滚等信息。

创建事物DataSourceTransactionObject

事物拦截器中有一个私有成员变量,private final ConcurrentMap<Object, PlatformTransactionManager> transactionManagerCache,该变量中记录系统配置的事物管理器。目前系统配置的是org.springframework.jdbc.datasource.DataSourceTransactionManager,事物的创建主要交给事物管理器DataSourceTransactionManager来完成,

    protected Object doGetTransaction() {
        DataSourceTransactionManager.DataSourceTransactionObject txObject = new DataSourceTransactionManager.DataSourceTransactionObject();
        txObject.setSavepointAllowed(this.isNestedTransactionAllowed());
        ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(this.dataSource);
        txObject.setConnectionHolder(conHolder, false);
        return txObject;
    }

通过new关键字来创建事物对象DataSourceTransactionObject,这个对象是事务管理器的一个内部类。

创建事物状态DefaultTransactionStatus

接着创建事物状态DefaultTransactionStatus,通过new关键创建事物状态对象,new DefaultTransactionStatus( transaction, newTransaction,actualNewSynchronization,definition.isReadOnly(), debug, suspendedResources);

事物状态创建完成之后,就从数据源DruidDataSource对象中的连接池中获取一个连接DruidConnectionHolder,连接池是一个数组,private volatile DruidConnectionHolder[] connections,这个connections数组中的连接是什么时候创建的呢?看看我们的bean.xml当中数据源的配置:

    <bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
          destroy-method="close" parent="dbCommProperty">
        <property name="url"
                  value="jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&amp;characterEncoding=utf8&amp;allowMultiQueries=true"/>
        <property name="username" value="1111111"/>
        <property name="password" value="1111111"/>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    </bean>

数据源DruidDataSource在实例化之后,spring会调用bean配置的初始化方法,此处配置的init-method="init",表达的意思就是调用数据源DruidDataSource的init()方法,完成数据源的初始化。DruidDataSource在获取到DruidConnectionHolder连接之后,又将其封装成为DruidPooledConnection对象,之后在返回给事务管理器。

事务管理器在拿到连接之后,将连接的自动提交设置为false,con.setAutoCommit(false),关闭自动提交。

接着调用事物同步管理器TransactionSynchronizationManager,将当前的连接绑定在当前线程,通过ThreadLocal来实现,事物同步管理器内部定义了一个私有的成员变量,private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<Map<Object, Object>>("Transactional resources"),用来将当前的数据源连接和当前线程绑定。Map<Object, Object>中的key就是DruidDataSource对象,value就是当前获取到的数据源连接ConnectionHolder,

事物同步管理器TransactionSynchronizationManager中还定义了很多这样的ThreadLocal,用来缓存当前线程、当前事物所处的状态信息:

public abstract class TransactionSynchronizationManager {

	private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);

	private static final ThreadLocal<Map<Object, Object>> resources =
			new NamedThreadLocal<Map<Object, Object>>("Transactional resources");

	private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
			new NamedThreadLocal<Set<TransactionSynchronization>>("Transaction synchronizations");

	private static final ThreadLocal<String> currentTransactionName =
			new NamedThreadLocal<String>("Current transaction name");

	private static final ThreadLocal<Boolean> currentTransactionReadOnly =
			new NamedThreadLocal<Boolean>("Current transaction read-only status");

	private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
			new NamedThreadLocal<Integer>("Current transaction isolation level");

	private static final ThreadLocal<Boolean> actualTransactionActive =
			new NamedThreadLocal<Boolean>("Actual transaction active");
}

创建事物信息TransactionInfo

接下来就是事物拦截器TransactionInterceptor,创建事物信息new TransactionInfo(tm, txAttr, joinpointIdentification),事物信息TransactionInfo内部有一个成员变量TransactionInfo oldTransactionInfo,此变量保存着上一个事物信息的引用。

以上几个类的类图如下:

调用目标方法

和事物相关的类创建和组装完成之后,就进入到调用目标方法的阶段。但是调用目标方法的地方并不在事物拦截器TransactionInterceptor中,而是在CglibAopProxy$CglibMethodInvocation类中的proceed()方法,事物拦截器中invokeWithinTransaction()方法只是定义了事物执行的流程,在回顾一下这段代码:

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
			throws Throwable {
        //获取事物属性
		final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
        //获取事物管理器
		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
		final String joinpointIdentification = methodIdentification(method, targetClass);
        //创建事物信息
		TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
			Object retVal = null;
			try {
                //调用目标方法
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				cleanupTransactionInfo(txInfo);
			}
			commitTransactionAfterReturning(txInfo);
			return retVal;
	}

调用invocation.proceedWithInvocation()的目的就是调用目标的方法,但是这是怎么回到CglibAopProxy$CglibMethodInvocation类的proceed()的方法的呢?

事物拦截器TransactionInterceptor的invoke方法中,直接调用了invokeWithinTransaction()方法,invokeWithinTransaction()方法只是定义事物执行的流程。但是传入的参数中有一个匿名类new InvocationCallback(),在这个匿名类的proceedWithInvocation()方法中调用了invocation.proceed(),这个invocation是什么对象呢?它其实引用的就是CglibAopProxy$CglibMethodInvocation对象实例。

public Object invoke(final MethodInvocation invocation) throws Throwable {

		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

		return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
			@Override
			public Object proceedWithInvocation() throws Throwable {
				return invocation.proceed();
			}
		});
	}

通过以上的代码设计,就自然回到了CglibAopProxy$CglibMethodInvocation的proceed()方法中,以下代码有忽略。

    public Object proceed() throws Throwable {
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return this.invokeJoinpoint();
        }
    }

回到proceed()方法之后,就执行this.invokeJoinpoint(),因为interceptorsAndDynamicMethodMatchers集合中所有的拦截器已经执行完成,invokeJoinpoint()方法中的内容就是去调用我们的目标方法。

我们在来梳理一下这个调用过程:

可以看出CglibAopProxy.CglibMethodInvocation.proceed()这个方法,被调用了多次,除了第一次调用,后面的几次调用都是在拦截器中通过回调的方式执行的,这样的调用方法增加了的类耦合性,为什么这样设计呢?为什么不直接通过for循环调用拦截器呢,我想这是因为这种回调的方式,形成了一个调用链,如果我们的目标方法抛出异常了之后,在这个链条上的拦截器都能收到异常信息,拦截器中可以根据异常信息作出自己的处理逻辑,事物拦截器如果要控制事物的流程,就必须知道目标方法执行正常与否,如果目标方法执行正常,事物正常提交,如果目标方式执行异常,事物回滚。

提交事物

目标方法AuthUserServiceImpl.delete()执行完成之后,根据调用的链,程序又会回到TransactionInterceptor.invoke()方法,在这个方法中执行事物的提交逻辑。大致做了以下几件事情:

  1. 调用connection的commit()方法,执行提交操作
  2. 释放当前连接connection到连接池中
  3. 设置事物状态DefaultTransactionStatus的的成员变量boolean completed = true
  4. 清理事物同步管理器TransactionSynchronizationManager中的缓存状态,解除当前线程绑定的连接connection
  5. 恢复当前连接connection的默认设置,比如自动提交状态设置为true,boolean autoCommit = true

事物创建过程的时序图如下,不代表实际的执行过程,意在说明问题:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值