基于SpringBoot的Spring事务实现原理

基于SpringBoot的Spring事务实现原理

jar包版本

  • spring-boot-starter-web 2.1.3.RELEASE
    • spring-aop 5.1.5.RELEASE
  • spring-boot-starter-jdbc 2.1.3.RELEASE
    • spring-jdbc 5.1.5.RELEASE

Spring事务概述

spring事务是在spring aop切面代理以及spring jdbc的基础上构建的。因此在了解事务的实现原理之前必须对这3个架构有一定的了解

源码分析

要开启Spring事务需要添加注解@EnableTransactionManagement

  • EnableTransactionManagement
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
        //是否直接代理目标class(即通过cglib代理),默认先通过接口代理。
	boolean proxyTargetClass() default false;
        //代理模式PROXY(JDK) ,ASPECTJ
	AdviceMode mode() default AdviceMode.PROXY;
	
	int order() default Ordered.LOWEST_PRECEDENCE;
}

通过注解的属性名称可以猜测属性的作用,具体逻辑在后续的代码实现中进行分析。通过这个注解可以看到是@Import(TransactionManagementConfigurationSelector.class)了一个类,因此直接看这个类。

  • TransactionManagementConfigurationSelector
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
    protected String[] selectImports(AdviceMode adviceMode) {
            switch (adviceMode) {
                case PROXY:
                    return new String[] {AutoProxyRegistrar.class.getName(),
                            ProxyTransactionManagementConfiguration.class.getName()};
                case ASPECTJ:
                    return new String[] {determineTransactionAspectClass()};
                default:
                    return null;
            }
        }
}

public abstract class AdviceModeImportSelector<A extends Annotation> implements ImportSelector {
    @Override
    public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //获取类上泛型类型(即EnableTransactionManagement)
        Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
        Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");
        //从当前正在注入的bean中的所有注解中获取EnableTransactionManagement注解的属性
        AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
        if (attributes == null) {
            throw new IllegalArgumentException(String.format(
                    "@%s is not present on importing class '%s' as expected",
                    annType.getSimpleName(), importingClassMetadata.getClassName()));
        }
        //从EnableTransactionManagement注解的属性获取mode属性值
        AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());
        //由子类实现
        String[] imports = selectImports(adviceMode);
        if (imports == null) {
            throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
        }
        return imports;
    }
}

其实这里逻辑很简单,获取class上EnableTransactionManagement的注解AdviceMode属性,根据不同的配置去注入不同的bean实现。
(至于import实现是怎么实现的,逻辑在ConfigurationClassPostProcessor中,这里不做展开,属于spring容器的基础内容,在这里只要知道spring通过selectImports方法将返回的bean注入到spring容器中)

  • AutoProxyRegistrar
//省略不重要代码
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
                Boolean.class == proxyTargetClass.getClass()) {
            candidateFound = true;
            if (mode == AdviceMode.PROXY) {
                AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                if ((Boolean) proxyTargetClass) {
                    AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                    return;
                }
            }
        }
    }
}
public abstract class AopConfigUtils {
    @Nullable
    public static BeanDefinition registerAutoProxyCreatorIfNecessary(
            BeanDefinitionRegistry registry, @Nullable Object source) {

        return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
    }
    @Nullable
    private static BeanDefinition registerOrEscalateApcAsRequired(
            Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
        RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
        beanDefinition.setSource(source);
        beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
        beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
        return beanDefinition;
    }
}

其核心逻辑就是当容器中不存在org.springframework.aop.config.internalAutoProxyCreator的时候默认注入InfrastructureAdvisorAutoProxyCreator的bean。从这里可以看出spring事务是必须要有aop的支持。

  • InfrastructureAdvisorAutoProxyCreator
    通过继承关系发现InfrastructureAdvisorAutoProxyCreator实现了SmartInstantiationAwareBeanPostProcessor接口并且扩展了postProcessAfterInitialization接口
    ,因此这里就是AOP的核心逻辑,在bean创建之后生成代理对象
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware { 
    @Override
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }
    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            Object proxy = createProxy(
                    bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }
        return bean;
    }
}

可以看出这里的逻辑是通过getAdvicesAndAdvisorsForBean方法获取到切面和切点,来判断是否需要创建代理。
这个方法的逻辑是从spring容器中获取Advisor,并且通过AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass)去决定是否需要
代理。其核心逻辑是Pointcut接口中获取MethodMatcher,并通过matcher接口方法来最终实现。而事务的advisor是BeanFactoryTransactionAttributeSourceAdvisor,
因此其matcher实现逻辑就在其中。后续分析

  • ProxyTransactionManagementConfiguration
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		advisor.setTransactionAttributeSource(transactionAttributeSource());
		advisor.setAdvice(transactionInterceptor());
		if (this.enableTx != null) {
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}
}

在这个Configuration中注入了BeanFactoryTransactionAttributeSourceAdvisor,通过继承关系可以发现其实就是Advisor。
在之前的AbstractAutoProxyCreator以来查找的Advisor就是这里注入的。
通过源码可以发现Spring的Advisor其实是组合了Pointcut和Advice而他们的具体实现分别是AnnotationTransactionAttributeSource和TransactionInterceptor。
其实到了这里AOP的基本组件都已经齐全了。之后具体看下Spring事务advice的具体是如何实现事务语意的。

  • TransactionInterceptor
    在分析这个源码之前,必须要先了解spring创建代理的实现,即cglib以及JDK动态代理,无论哪种实现方式在创建代理方法的时候都需要通过advisor中获取。
    List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)进而创建ReflectiveMethodInvocation来实现
    代理方法逻辑。在执行ReflectiveMethodInvocation#proceed实际调用的就是((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)。具体源码在这里不做分析,只要知道结果即可。
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
public Object invoke(MethodInvocation invocation) throws Throwable {
        Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
        return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
    }
}
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
    
    protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
    			final InvocationCallback invocation) throws Throwable {
        //获取注解属性
        TransactionAttributeSource tas = getTransactionAttributeSource();
        final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
        //获取TransactionManager,不设置的情况下默认取容器PlatformTransactionManager
        final PlatformTransactionManager tm = determineTransactionManager(txAttr);
        final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

        if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
            //此处源码比较复杂,数据库事务具体实现在spring-jdbc中不做展开,大致逻辑是初始化一个TransactionInfo里面初始化了事务的状态等信息
            //DataSourceTransactionManager会将connection的autocommit设置为false。
            TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
            Object retVal = null;
            try {
                //执行被代理对象方法逻辑
                retVal = invocation.proceedWithInvocation();
            }
            catch (Throwable ex) {
                //根据异常判断是回滚还是提交
                completeTransactionAfterThrowing(txInfo, ex);
                throw ex;
            }
            finally {
                //清除TransactionInfo
                cleanupTransactionInfo(txInfo);
            }
            //提交事务
            commitTransactionAfterReturning(txInfo);
            return retVal;
        }
    }
}

以上代码除了创建部分逻辑有些复杂,其他部分都是很好理解的。这里为止spring事务原理分析就结束了,当然其中还有许多细节还未分析。

总结

spring事务借助了spring容器,spring-aop模块以及TransactionManager的实现类帮助开发者只需要通过Trancastion注解即可自动在方法前开启事务,
在异常回滚事务,方法结束执行事务。不需要开发者手动的编写这些重复的事务代码,提升开发效率。通过了解他的实现原理也能规避一些使用上的错误,从而导致事务的失效等问题。
后续也许会为spring-aop单独在写一篇吧

你可能感兴趣的:(spring,java,spring,boot,aop)