springboot注解事务实现原理

AopAutoConfiguration
@EnableAspectJAutoProxy

@lazy,被这个注解标注的bean不会立即加载到单例池
如果在构造方法或者依赖注入的时候,会优先注入懒加载的代理对象
ContextAnnotationAutowireCandidateResolver实现,
如果需要懒加载的话,先判断是否可以懒加载,是的话返回代理对象,否的话返回null,然后走正常获取bean流程
真正使用的时候,会从beanfactory中获取真正的bean

个人理解,可能有不对的地方。

1,入口

在spring的自动配置里配置了类TransactionAutoConfiguration,

这个类的内部类EnableTransactionManagementConfiguration标注了是一个配置类,

该配置类注入的bean,使用了注解@EnableTransactionManagement,根据不同的配置项,确定事务代理走cglib还是jdk

2,后置处理与切面类

在注解@EnableTransactionManagement上,使用了@Import注入了TransactionManagementConfigurationSelector类,

该类确定了spring对包含事务注解的对象的处理逻辑。

在注解EnableTransactionManagement中的AdviceMode中,默认值为PROXY,走类似于ProxyFactory的处理逻辑

通过AutoProxyRegistrar类,向环境中注入类AbstractAdvisorAutoProxyCreator的子类,用来实现对事务注解类的代理处理。

如果走cglib,则会修改bean定义信息,增加proxyTargetClass值为true

通过ProxyTransactionManagementConfiguration类,定义切面逻辑与事务注解信息解析类

3,事务注解代理逻辑

AbstractAdvisorAutoProxyCreator类实现了SmartInstantiationAwareBeanPostProcessor,可以对bean进行后置处理。

//如果早期引用,则提前代理并返回代理对象
public Object getEarlyBeanReference(Object bean, String beanName) {
        Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
        this.earlyProxyReferences.put(cacheKey, bean);
        return this.wrapIfNecessary(bean, beanName, cacheKey);
    }


public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
        if (bean != null) {
            //缓存键
            Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
            //如果被早期引用,则返回原始bean,这一步的逻辑其实就是为了解决循环依赖
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                //如果需要的话,返回代理对象
                return this.wrapIfNecessary(bean, beanName, cacheKey);
            }
        }

        return bean;
    }

 protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
            return bean;
        } else if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
        } else if (!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) {
            //从beanfactory中找到所有可以使用的Advisor,如果当前bean包含事务注解,这一步会找到事务处理的切面类对象
            //会通过AopUtils的canApply方法匹配切面,匹配了则返回该对象
            Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);
            if (specificInterceptors != DO_NOT_PROXY) {
                this.advisedBeans.put(cacheKey, Boolean.TRUE);
                //创建代理对象并返回,使用了ProxyFactory进行代理对象的创建
                Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
                this.proxyTypes.put(cacheKey, proxy.getClass());
                return proxy;
            } else {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return bean;
            }
        } else {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }
    }
4,切面逻辑

AnnotationTransactionAttributeSource:解析事务注解

BeanFactoryTransactionAttributeSourceAdvisor:切面判定

TransactionInterceptor:事务处理逻辑,实现了MethodInterceptor类

带事务注解的类或方法执行的时候,进入代理invoke方法,进而执行方法invokeWithinTransaction

//TransactionInterceptor,省掉了看不懂的逻辑
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final TransactionAspectSupport.InvocationCallback invocation) throws Throwable {
   	//获取事务解析对象
    TransactionAttributeSource tas = this.getTransactionAttributeSource();
    //获取事务注解的参数    
    TransactionAttribute txAttr = tas != null ? tas.getTransactionAttribute(method, targetClass) : null;
    //获取事务管理器    
    TransactionManager tm = this.determineTransactionManager(txAttr);         
    PlatformTransactionManager ptm = this.asPlatformTransactionManager(tm);
    //应该是事务的名称        
    String joinpointIdentification = this.methodIdentification(method, targetClass, txAttr);
    //创建事务信息,,或者加入一个已有的事务,如果需要的话                
    TransactionAspectSupport.TransactionInfo txInfo = this.createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

                Object retVal;
                try {
                    //执行原来的方法
                    retVal = invocation.proceedWithInvocation();
                } catch (Throwable var20) {
                    //事务信息不为空的话,如果异常则回滚,如果嵌套的话,还原事务,
                    //并触发TransactionSynchronizationManager.getSynchronizations()的对象方法
                    this.completeTransactionAfterThrowing(txInfo, var20);
                    throw var20;
                } finally {
                    //清空事务信息
                    this.cleanupTransactionInfo(txInfo);
                }
				//判断返回值是否属于vavr包的Try类,如果是的话,做出一些处理,因为异常会被Try.of方法捕获
    			//所以这里需要主动调用Try类onFailure方法,如果真的执行异常了,就设置事务回滚
                if (retVal != null && vavrPresent && TransactionAspectSupport.VavrDelegate.isVavrTry(retVal)) {
                    TransactionStatus status = txInfo.getTransactionStatus();
                    if (status != null && txAttr != null) {
                        retVal = TransactionAspectSupport.VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
                    }
                }
				//事务信息不为空的话,提交事务,或者回滚,如果嵌套的话,还原事务
    			//并触发TransactionSynchronizationManager.getSynchronizations()的对象方法
                this.commitTransactionAfterReturning(txInfo);
                return retVal;
            }
        }
    }
//TransactionInterceptor
protected TransactionAspectSupport.TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
        if (txAttr != null && ((TransactionAttribute)txAttr).getName() == null) {
            txAttr = new DelegatingTransactionAttribute((TransactionAttribute)txAttr) {
                public String getName() {
                    return joinpointIdentification;
                }
            };
        }

        TransactionStatus status = null;
        if (txAttr != null) {
            if (tm != null) {
                //从事务管理器中获取事务状态
                status = tm.getTransaction((TransactionDefinition)txAttr);
            } else if (this.logger.isDebugEnabled()) {
                this.logger.debug("Skipping transactional joinpoint [" + joinpointIdentification + "] because no transaction manager has been configured");
            }
        }
		//准备事务信息
        return this.prepareTransactionInfo(tm, (TransactionAttribute)txAttr, joinpointIdentification, status);
    }
//AbstractPlatformTransactionManager,某些具体方法实现可参考DataSourceTransactionManager    
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
    //事务信息    
    TransactionDefinition def = definition != null ? definition : TransactionDefinition.withDefaults();
    //开始事务,获取事务对象,由子类实现    
    Object transaction = this.doGetTransaction();
	boolean debugEnabled = this.logger.isDebugEnabled();
    //如果存在事务信息,进行一些不同的处理
    if (this.isExistingTransaction(transaction)) {
        //逻辑应该是,判断加入当前事务还是新事务之类的
        return this.handleExistingTransaction(def, transaction, debugEnabled);
    } else if (def.getTimeout() < -1) {   
        throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
    } else if (def.getPropagationBehavior() == 2) {   
        throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'");
        //如果事务传播等级不是这几个值,做某些处理
    } else if (def.getPropagationBehavior() != 0 && def.getPropagationBehavior() != 3 && def.getPropagationBehavior() != 6) {    
        if (def.getIsolationLevel() != -1 && this.logger.isWarnEnabled()) {      
            this.logger.warn("Custom isolation level specified but no actual transaction initiated; isolation level will effectively be ignored: " + def);   
        }   
        boolean newSynchronization = this.getTransactionSynchronization() == 0;  
        return this.prepareTransactionStatus(def, (Object)null, true, newSynchronization, debugEnabled, (Object)null);   
    } else {    
        AbstractPlatformTransactionManager.SuspendedResourcesHolder suspendedResources = this.suspend((Object)null);    
        if (debugEnabled) {   
            Log var10000 = this.logger;  
            String var10001 = def.getName();  
            var10000.debug("Creating new transaction with name [" + var10001 + "]: " + def);
        }
        try {   
            //开始事务
            return this.startTransaction(def, transaction, debugEnabled, suspendedResources); 
        } catch (Error | RuntimeException var7) { 
            this.resume((Object)null, suspendedResources);  
            throw var7;   
        }  
    }
}
//DataSourceTransactionManager
protected Object doGetTransaction() {
    //创建一个新的事务对象
    DataSourceTransactionManager.DataSourceTransactionObject txObject = new DataSourceTransactionManager.DataSourceTransactionObject();  
    //设置事务对象是否支持保存点
    txObject.setSavepointAllowed(this.isNestedTransactionAllowed());
    //获取数据库连接,如果是第一次,此处则不会持有连接
    //这里取的是key是DataSource对象,
    //比如说mybatis的事务处理,调用DataSourceUtils.getConnection方法传递的也是DataSource对象,调到getResource方法
    //如果mybatis和事务管理器使用的不是一个DataSource对象,或者不在一个线程内,会导致事务失效
    //如果不主动创建事务管理器,会由springboot的DataSourceTransactionManagerAutoConfiguration创建
    ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(this.obtainDataSource()); 
    //默认标注不是新连接
    txObject.setConnectionHolder(conHolder, false); 
    return txObject;
}
//AbstractPlatformTransactionManager
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled, @Nullable AbstractPlatformTransactionManager.SuspendedResourcesHolder suspendedResources) {   
    boolean newSynchronization = this.getTransactionSynchronization() != 2;
    //创建一个事务状态对象
    DefaultTransactionStatus status = this.newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
    //准备开始
    this.doBegin(transaction, definition);
    //如果是新的事务,设置一些对象到TransactionSynchronizationManager的一些ThreadLoal变量中
    this.prepareSynchronization(status, definition);
    return status;    
}
//DataSourceTransactionManager
protected void doBegin(Object transaction, TransactionDefinition definition) {
        DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)transaction;
        Connection con = null;

        try {
            //如果是第一次,则ConnectionHolder是null,这里会获取一个信息的连接并设置到事务对象里
            //如果原来存在ConnectionHolder且是有事务的,也重新创建一个ConnectionHolder,暂不清楚什么情况下走这个逻辑
            if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
                Connection newCon = this.obtainDataSource().getConnection();
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
                }

                txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
            }

            txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
            con = txObject.getConnectionHolder().getConnection();
            //根据事务定义设置连接属性
            Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
            txObject.setPreviousIsolationLevel(previousIsolationLevel);
            txObject.setReadOnly(definition.isReadOnly());
            if (con.getAutoCommit()) {
                //是用来还原原先的连接属性
                txObject.setMustRestoreAutoCommit(true);
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
                }
				//设置非自动提交
                con.setAutoCommit(false);
            }
			//如果只读,则设置只读
            this.prepareTransactionalConnection(con, definition);
            txObject.getConnectionHolder().setTransactionActive(true);
            int timeout = this.determineTimeout(definition);
            if (timeout != -1) {
                //设置超时
                txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
            }

            if (txObject.isNewConnectionHolder()) {
                //如果是新连接,绑定到TransactionSynchronizationManager的resources变量
                TransactionSynchronizationManager.bindResource(this.obtainDataSource(), txObject.getConnectionHolder());
            }

        } catch (Throwable var7) {
            if (txObject.isNewConnectionHolder()) {
                DataSourceUtils.releaseConnection(con, this.obtainDataSource());
                txObject.setConnectionHolder((ConnectionHolder)null, false);
            }

            throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", var7);
        }
    }
//TransactionInterceptor    
protected TransactionAspectSupport.TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, String joinpointIdentification, @Nullable TransactionStatus status) {
//创建事务信息
TransactionAspectSupport.TransactionInfo txInfo = new TransactionAspectSupport.TransactionInfo(tm, txAttr, joinpointIdentification);
        if (txAttr != null) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
            }
			//设置事务状态
            txInfo.newTransactionStatus(status);
        } else if (this.logger.isTraceEnabled()) {
            this.logger.trace("No need to create transaction for [" + joinpointIdentification + "]: This method is not transactional.");
        }
		//事务信息绑定到当前线程,利用ThreadLocal
        txInfo.bindToThread();
        return txInfo;
    }
事务嵌套,以DataSourceTransactionManager为例
事务信息(TransactionInfo)包含事务状态(TransactionStatus)和事务管理器(PlatformTransactionManager),
事务状态包含事务对象(Object txObject),
事务对象包含连接持有(ConnectionHolder)
多个事务持有的数据库连接其实是同一个,
当有一个事务异常的时候,如果事务状态是新的,那么就回滚,
如果事务状态不是新的,则通过事务对象持有的公共ConnectionHolder的rollbackOnly,设置为true,
最终事务完成的时候判断该状态,进行回滚或提交
如果事务嵌套,cleanupAfterCompletion方法中进行事务还原
事务传播等级参考地址:https://blog.csdn.net/qq_38287371/article/details/119001292
0:REQUIRED(默认) 可单独成一事务。若被其他事务包裹则加入该事务,成为其一部分。(平等加入,独立亦可成事务,自成融合)
若嵌套执行的方法要求一起成功或者回滚,则选择本传播级别。
1:SUPPORTS 单独不能成事务,只能依赖其他事务,成为其事务的一部分。(依赖加入,独立不能成事务,依附融合)
若嵌套执行的方法要求一起成功或者回滚,单独执行时候以非事务方式执行,则选择本事物级别。
2:MANDATORY 只能成为其他事务的一部分,单纯执行将报错。(强制加入,独立不可执行。寄生融合)
若嵌套执行的方法要求一起执行成功或者一起回滚,不允许以不被事务包裹方式执行,则选择该事物传播级别。
3:REQUIRED_NEW 无论如何都新建一个事务,与其他事务间互不影响。(始终独立成事务,自成自闭)
若嵌套执行的方法要求各自事务独立,互不影响,则选择本传播级别。
4:NOT_SUPPORTED 当前方法不应该有事务,如果有事务存在,将它挂起,以无事务状态运行 (可被吞并,始终不支持事务。)
(无事务,就是指底层的Connection对象的autoCommit、isolation等属性与数据库有关,与dataSource设置的属性有关,不会被Spring改变。)
若嵌套执行的方法要求内部嵌套方法不会对外部方法事务造成影响并且内部方法不需要事务,单独执行时候亦以非事务方式执行,则选择该事物传播级别。
5:NEVER 被事务强制包裹则抛出异常,单独执行时候必须以非事务方式执行。(不可被吞并,始终不支持事务。)
若嵌套执行的方法要求内部方法不允许在事务中执行,单独执行时候必须以非事务方式执行,则选择该事物传播级别。
6:NESTED 如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则,就启动一个新的事务,并在它自己的事务内运行。(独立亦可成事务)
若嵌套执行的方法要求内部方法出错只回滚自己,外部方法执行失败回滚所有,单独执行时候自动开启一个执行,则选择该事物传播级别。
//AbstractPlatformTransactionManager
private TransactionStatus handleExistingTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException {
        if (definition.getPropagationBehavior() == 5) {
            throw new IllegalTransactionStateException("Existing transaction found for transaction marked with propagation 'never'");
        } else {
            AbstractPlatformTransactionManager.SuspendedResourcesHolder suspendedResources;
            if (definition.getPropagationBehavior() == 4) {
                if (debugEnabled) {
                    this.logger.debug("Suspending current transaction");
                }

                suspendedResources = this.suspend(transaction);
                boolean newSynchronization = this.getTransactionSynchronization() == 0;
                return this.prepareTransactionStatus(definition, (Object)null, false, newSynchronization, debugEnabled, suspendedResources);
            } else if (definition.getPropagationBehavior() == 3) {
                if (debugEnabled) {
                    this.logger.debug("Suspending current transaction, creating new transaction with name [" + definition.getName() + "]");
                }

                suspendedResources = this.suspend(transaction);

                try {
                    return this.startTransaction(definition, transaction, debugEnabled, suspendedResources);
                } catch (Error | RuntimeException var6) {
                    this.resumeAfterBeginException(transaction, suspendedResources, var6);
                    throw var6;
                }
            } else if (definition.getPropagationBehavior() == 6) {
                if (!this.isNestedTransactionAllowed()) {
                    throw new NestedTransactionNotSupportedException("Transaction manager does not allow nested transactions by default - specify 'nestedTransactionAllowed' property with value 'true'");
                } else {
                    if (debugEnabled) {
                        this.logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
                    }

                    if (this.useSavepointForNestedTransaction()) {
                        DefaultTransactionStatus status = this.prepareTransactionStatus(definition, transaction, false, false, debugEnabled, (Object)null);
                        status.createAndHoldSavepoint();
                        return status;
                    } else {
                        return this.startTransaction(definition, transaction, debugEnabled, (AbstractPlatformTransactionManager.SuspendedResourcesHolder)null);
                    }
                }
            } else {
                if (debugEnabled) {
                    this.logger.debug("Participating in existing transaction");
                }

                if (this.isValidateExistingTransaction()) {
                    if (definition.getIsolationLevel() != -1) {
                        Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
                        if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
                            Constants isoConstants = DefaultTransactionDefinition.constants;
                            throw new IllegalTransactionStateException("Participating transaction with definition [" + definition + "] specifies isolation level which is incompatible with existing transaction: " + (currentIsolationLevel != null ? isoConstants.toCode(currentIsolationLevel, "ISOLATION_") : "(unknown)"));
                        }
                    }

                    if (!definition.isReadOnly() && TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
                        throw new IllegalTransactionStateException("Participating transaction with definition [" + definition + "] is not marked as read-only but existing transaction is");
                    }
                }

                boolean newSynchronization = this.getTransactionSynchronization() != 2;
                return this.prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, (Object)null);
            }
        }
    }
事务嵌套逻辑
0:嵌套时加入当前事务,一起提交或回滚
1:首个方法,在getTransaction方法开事务的时候判断,不等于0/3/6的时候,不传递事务对象,
非首个方法,进入handleExistingTransaction方法,加入当前事务
2:首个方法,在getTransaction方法开事务的时候判断,如果传播等级等于2且不存在事务,报错抛出异常
非首个方法,进入handleExistingTransaction方法,加入当前事务
3:首个方法,在getTransaction方法开事务的时候判断,创建一个新事务
非首个方法,进入handleExistingTransaction方法的等于3的逻辑中,把当前事务信息保存下来,创建一个新的事务,在这个新的事务执行后,还原之前的事务,从而做到嵌套事务之间互不影响。
4:首个方法,在getTransaction方法开事务的时候判断,不等于0/3/6的时候,不传递事务对象,
非首个方法,进入handleExistingTransaction方法的等于4的逻辑中,把当前事务信息保存下来,创建一个新的事务,新事务不包含事务对象,在这个新的事务执行后,还原之前的事务,从而做到挂起之前的事务。
5:首个方法,在getTransaction方法开事务的时候判断,不等于0/3/6的时候,不传递事务对象,
非首个方法,进入handleExistingTransaction方法的等于5分支,抛出异常
6:首个方法,在getTransaction方法开事务的时候判断,创建一个新事务
非首个方法,进入handleExistingTransaction方法的等于6的逻辑中,
(savepoint,将当前事务切割为更小的事务单位)
如果支持savepoint,标记不是新事务,设置保存点,当前事务异常时,回滚数据到保存点,当前事务没有异常时,程序继续,如果之前的事务方法异常则统一回滚,没有异常则提交
不支持保存点的逻辑不是很明白,DataSourceTransactionManager也不会走到这里。
大概就是会以新事务的形式继续,但走到TransactionSynchronizationManager.bindResource的方法时候会报错抛出异常,因为当前已经有事务信息存在了。
然后进入异常方法,释放数据库连接,此时因为TransactionSynchronizationManager.bindResource的数据已经被改变了,之前的ConnectionHolder信息会丢失,现在的ConnectionHolder持有的连接和用来判断的连接一致,所以当前连接会被释放掉,之前的事务继续的时候,拿到的数据库连接是已关闭状态。
如果反复这样操作几次,数据库连接就会被耗尽,因为之前拿到的ConnectionHolder中的数据库连接没有还回去。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值