Spring事务源码分析&责任链事务链&事务不生效

本文详细分析了Spring事务的源码,包括如何通过AOP责任链模式实现事务管理,TransactionInterceptor的调用过程,以及TransactionInfo在事务链中的作用。还探讨了在多线程环境下事务的挑战,以及事务不生效的几种情况,如非代理对象、无@Transactional注解等。
摘要由CSDN通过智能技术生成

前言

带着问题分析源码

  • Spring是如何管理事务的
  • 在多线程下事务会怎么样
  • 什么情况下事务不生效

事务源码分析

寻找Spring事务源码类

  • 简单讲一下如何快速分析事务源码 其实很简单 将断点打到service方法中 查看方法调用栈即可
  • 根据关键字 Transaction 找到TransactionInterceptor 即是源码分析入口在这里插入图片描述

TransactionInterceptor调用栈

问题? 方法是如何一步一步执行到TransactionInterceptor的

从上图方法调用栈可知 UserService首先被SpringAOP代理
被Spring管理的对象一般情况下都会被代理 在Spring中对象被代理有两种方式

  • JDK 动态代理
  • Cglib 动态代理

调用代理对象的方法都会被SpringAOP拦截 从而进入如下方法
org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
   
	Object oldProxy = null;
	boolean setProxyContext = false;
	Object target = null;
	TargetSource targetSource = this.advised.getTargetSource();
	try {
   
		if (this.advised.exposeProxy) {
   
			// Make invocation available if necessary.
			oldProxy = AopContext.setCurrentProxy(proxy);
			setProxyContext = true;
		}
		// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
		target = targetSource.getTarget();
		Class<?> targetClass = (target != null ? target.getClass() : null);
		// 获取代理对象的拦截器链 责任链模式
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
		Object retVal;
		// Check whether we only have one InvokerInterceptor: that is,
		// no real advice, but just reflective invocation of the target.
		if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
   
		     //如果目标方法没有拦截器链则直接执行目标方法
			// We can skip creating a MethodInvocation: just invoke the target directly.
			// Note that the final invoker must be an InvokerInterceptor, so we know
			// it does nothing but a reflective operation on the target, and no hot
			// swapping or fancy proxying.
			Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
			retVal = methodProxy.invoke(target, argsToUse);
		}
		else {
   
		     //创建方法方法调用对象 
		     //我们看到chain对象已经在构造方法的入参 是实现责任链调用的关键
			// We need to create a method invocation...
			retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
		}
		//获取方法调用结果
		retVal = processReturnType(proxy, target, method, retVal);
		return retVal;
	}
	finally {
   
		if (target != null && !targetSource.isStatic()) {
   
			targetSource.releaseTarget(target);
		}
		if (setProxyContext) {
   
			// Restore old proxy.
			AopContext.setCurrentProxy(oldProxy);
		}
	}
}
  • 674行 获取拦截器链 责任链模式在各种框架中大量应用 Okhttp Netty Dubbo
    • List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)

    • 我们先看返回结果
      org.springframework.transaction.interceptor.TransactionInterceptor
      在这里插入图片描述

问题? TransactionInterceptor是怎么加入到AOP 拦截器链中的
答案在getInterceptorsAndDynamicInterceptionAdvice方法中我们来简单分析一下
org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice

  • 调用栈如下
    org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept
    #674 org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice
    ##483 org.springframework.aop.framework.AdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice
    ###    org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice
    
  • 源码分析
    //中间省略了部分源码 
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
    	Advised config, //AOP代理配置的抽象 org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor 
    	Method method, //代理对象方法 public java.lang.Integer com.deanjo.service.UserServiceImpl.updateById(com.deanjo.share.param.UserModifyParam)
    	@Nullable Class<?> targetClass) //代理目标类 com.deanjo.service.UserServiceImpl
    {
         
        //具体的代理配置的实现
        //org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor 事务代理配置实
        Advisor[] advisors = config.getAdvisors();
        //拦截器链
        List<Object> interceptorList = new ArrayList<>(advisors.length);
        for (Advisor advisor : advisors) {
         
            //PointcutAdvisor 我们常用的AOP日志拦截 对切入点进行拦截
    		// BeanFactoryTransactionAttributeSourceAdvisor instanceof PointcutAdvisor)
            if (advisor instanceof PointcutAdvisor) {
          
           		 //TransactionInterceptor就是再这里获取到的 并加入到拦截器链中
    			 //方法上或者类上必须要有 注解 @Transactional
    		     //事务通过xml配置都会将 TransactionInterceptor加入到AOP拦截器链中
    
                ...
            }else if (advisor instanceof IntroductionAdvisor) {
         
               //IntroductionAdvisor 对目标类增加新的属性和行为 本人没用过
               //是不是pinpointhe和skywalking这类链路追踪框架会用 后面再专门研究
            }else {
         
                //AOP的通用拦截器
    			Interceptor[] interceptors = registry.getInterceptors(advisor);
    			interceptorList.addAll(Arrays.asList(interceptors));
    		
    		}
        }
       return interceptorList;
    }
    
    • 核心逻辑
      • 通过各个具体的Advisors去获取org.aopalliance.intercept.Interceptor拦截器
      • 方法上或者类上如有有 @Transactional注解
        或者过xml配置都会将 TransactionInterceptor加入到AOP拦截器链中

分析Spring AOP责任链

通过创建CglibMethodInvocation对象实现责任链调用
org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept

  • 688行 创建责任链 并执行 各种源码框架对责任链的实现大同小异
    //创建责任链调用对象 CglibMethodInvocation 并开始调用proceed
    retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
    	 
     //CglibMethodInvocation 构造方法
    public CglibMethodInvocation(Object proxy,
    							  @Nullable Object target, 
    							  Method method,
    							  Object[] arguments, 
    							  @Nullable Class<?> targetClass,
    							  List<Object> interceptorsAndDynamicMethodMatchers, // 拦截器链
    							  MethodProxy methodProxy) {
         
    
    	  super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
    
    	  // Only use method proxy for public methods not derived from java.lang.Object
    		this.methodProxy = (Modifier.isPublic(method.getModifiers()) &&
    				method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) &&
    				!AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method) ?
    				methodProxy : null);
     }
    
  • 执行责任链调用 org.springframework.aop.framework.ReflectiveMethodInvocation#proceed
    public Object proceed() throws Throwable {
         
         // 责任链 如果当前链的索引等于责任链的长度则当前链是最后一个链执行完成后直接返回
    	//	We start with an index of -1 and increment early.
    	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
         
    	    //执行目标方法
    		return invokeJoinpoint();
    	}
        // 获取链上的拦截器 默认从0开始递增
    	Object interceptorOrInterceptionAdvice =
    			this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
       //判断Advice是否是 InterceptorAndDynamicMethodMatcher 动态方法匹配拦截器 
       //下面是InterceptorAndDynamicMethodMatcher的结构 这里具体的使用场景欢迎交流
       /* class InterceptorAndDynamicMethodMatcher {
    		final MethodInterceptor interceptor;
    		final MethodMatcher methodMatcher;
    		public InterceptorAndDynamicMethodMatcher(MethodInterceptor interceptor, MethodMatcher methodMatcher) {
    			this.interceptor = interceptor;
    			this.methodMatcher = methodMatcher;
    		}
    
    	}*/
       //TransactonIntercepters只是 MethodInterceptor
    	if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
         
    		// Evaluate dynamic method matcher here: static part will already have
    		// been evaluated and found to match.
    		InterceptorAndDynamicMethodMatcher dm =
    				(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
    		Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
    		if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
         
    			return dm.interceptor.invoke(this);
    		}else {
         
    			// Dynamic matching failed.
    			// Skip this interceptor and invoke the next in the chain.
    			return proceed();
    		}
    	}
    	// 当前链就是是一个方法拦截器 直接执行
    	else {
         
    		// It's an interceptor, so we just invoke it: The pointcut will have
    		// been evaluated statically before this object was constructed.
    		// 注意这里入参是 this 即当前业务方法 如下图 
    		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    	}
    }
    
    在这里插入图片描述

分析TransactionInterceptor源码

拦截器链TransactionInterceptor执行源码分析

public Object invoke(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, invocation::proceed);
	}

重点分析org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

/**
 * General delegate for around-advice-based subclasses, delegating to several other template
 * methods on this class. Able to handle {@link CallbackPreferringPlatformTransactionManager}
 * as well as regular {@link PlatformTransactionManager} implementations.
 * @param method the Method being invoked
 * @param targetClass the target class that we're invoking the method on
 * @param invocation the callback to use for proceeding with the target invocation
 * @return the return value of the method, if any
 * @throws Throwable propagated from the target invocation
 */
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
		final InvocationCallback invocation) throws Throwable {
   
    // 获取事务属性  事务传播机制 事务隔离级别 超时时间
	// If the transaction attribute is null, the method is non-transactional.
	TransactionAttributeSource tas =
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值