zoukankan      html  css  js  c++  java
  • Spring注解式事务解析

    Spring注解式事务解析


    1. 增加一个Advisor
      首先往Spring容器新增一个Advisor,BeanFactoryTransactionAttributeSourceAdvisor,它包含了TransactionInterceptor通知和TransactionAttributeSourcePointcut切点。TransactionAttributeSourcePointcut切点实际匹配使用了AnnotationTransactionAttributeSource这个类,它的作用是方法的切点匹配,解析Transactional注解,它尝试从当前类的方法,当前类,父接口方法,父接口查找Transactional注解,有则匹配到。

    2. AOP动态代理
      当普通bean实例化的时候,Spring通过AbstractAdvisorAutoProxyCreator的其中一个子类进行postProcessAfterInitialization进行AOP这个bean,织入匹配的Advisor,并生成动态代理。动态代理有2种,JdkDynamicAopProxy和ObjenesisCglibAopProxy。

    3. 拦截过程
      方法调用的时候,拿JdkDynamicAopProxy动态代理来讲,被动态代理的bean的公有方法调用会走invoke方法拦截,首先确定当前方法的拦截器链。

      			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
      

      如果上面的chain为空,不走拦截,否则走拦截责任链

      				invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
      				retVal = invocation.proceed();
      
    4. TransactionInterceptor事务拦截器
      内部拿到我们的TransactionInterceptor进行方法调用

      @Override
      	public Object invoke(final MethodInvocation invocation) throws Throwable {
      		// Work out the target class: may be {@code null}.
      		// The TransactionAttributeSource should be passed the target class
      		// as well as the method, which may be from an interface.
      		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
      
      		// Adapt to TransactionAspectSupport's invokeWithinTransaction...
      		return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
      			@Override
      			public Object proceedWithInvocation() throws Throwable {
      				return invocation.proceed();
      			}
      		});
      	}
      
    5.创建TransactionInfo对象
        他会先获取TransactionAttribute和PlatformTransactionManager,然后调用
        ```
        			TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
        ```
        内部逻辑为拿DataSourceTransactionManager举例,
        尝试从ThreadLocal获取ConnectionHolder(包含了一个Connection)
        ```
        protected Object doGetTransaction() {
        		DataSourceTransactionObject txObject = new DataSourceTransactionObject();
        		txObject.setSavepointAllowed(isNestedTransactionAllowed());
        		ConnectionHolder conHolder =
        				(ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
        		txObject.setConnectionHolder(conHolder, false);
        		return txObject;
        	}
        ```
        然后判断是不是新事务
        ```
        	if (isExistingTransaction(transaction)) {
        			// Existing transaction found -> check propagation behavior to find out how to behave.
        			return handleExistingTransaction(definition, transaction, debugEnabled);
        		}
        ```
        不是新事务,走handleExistingTransaction逻辑,内部会根据我们配置的传递规则做不同的处理,默认的Propagation.REQUIRED就会返回TransactionStatus对象标志为已存在的事务。
        是新事务则返回TransactionStatus对象标志为新事务,代码如下:
        ```
        	boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
        				DefaultTransactionStatus status = newTransactionStatus(
        						definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
        				doBegin(transaction, definition);
        				prepareSynchronization(status, definition);
        				return status;
        ```
        doBegin方法会从dataSource获取一个新连接,并设置到DataSourceTransactionObject的ConnectionHolder字段里,并且设置synchronizedWithTransaction和transactionActive为true代表新事务,然后设置con.setAutoCommit(false),最后设置ThreadLocal值,为当前ConnectionHolder。
        ```
        if (txObject.isNewConnectionHolder()) {
        				TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
        			}
        ```	
    6.责任链调用下一个拦截器 
        获取了当前的TransactionInfo开始走下一个拦截器
        ```
        	Object retVal = null;
        			try {
        				// This is an around advice: Invoke the next interceptor in the chain.
        				// This will normally result in a target object being invoked.
        				retVal = invocation.proceedWithInvocation();
        			}
        			catch (Throwable ex) {
        				// target invocation exception
        				completeTransactionAfterThrowing(txInfo, ex);
        				throw ex;
        			}
        ```
    7.提交或回滚
        处理完了之后如果抛异常根据匹配规则是否需要回滚,默认对RuntimeException和Error回滚。如果正常返回则调用commitTransactionAfterReturning方法
        ```
        protected void commitTransactionAfterReturning(TransactionInfo txInfo) {
        		if (txInfo != null && txInfo.hasTransaction()) {
        			if (logger.isTraceEnabled()) {
        				logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
        			}
        			txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
        		}
        	}
        ```
        进行commit,最后调用doCleanupAfterCompletion方法,清空ThreadLocal,设置con.setAutoCommit(true),并关闭连接。
  • 相关阅读:
    FJoi2017 1月21日模拟赛 comparison(平衡树+thita重构)
    juruo的刷题&博文祭
    [bzoj4247][挂饰] (动规+排序)
    FJoi2017 1月20日模拟赛 直线斯坦纳树(暴力+最小生成树+骗分+人工构造+随机乱搞)
    FJoi2017 1月20日模拟赛 交错和(等差数列+rmq)
    FJoi2017 1月20日模拟赛 恐狼后卫(口糊动规)
    【spoj 5971】lcmsum
    【bzoj 4025 改编版】graph
    【CF 718C】fibonacci
    【CF 482E】ELCA
  • 原文地址:https://www.cnblogs.com/yaojf/p/7423361.html
Copyright © 2011-2022 走看看