深入Spring事务源码剖析事务(一)

深入Spring事务源码剖析事务

事务简介

此篇文章需要有SpringAOP基础,知道AOP底层原理可以更好的理解Spring的事务处理。首先事务是什么呢?必须了解事务到底是什么,才能知道使用事务的场景和必要性。事务具有四个特性,称为ACID,分别是原子性一致性隔离性持久性,具体什么意思百度可以得到很多答案,这里简要概括一下。

  1. 就是事务可以保证一个事务内的所有操作,要么全部成功,要么就全部失败,这是原子性

  2. 并发多个事务时需要保证事务的更改要和另一个事务的更改保持一致,例如A、B、C都各有50元,一个事务中A给B转账50元,另一个事务中B给C转账50元,需要保证A中0元、B中50元、C中100元也就是总量还是150元,这就是一致性。而如果出现第一个事务中A转B 50元,另一个事务中B的账户不是100元而是50元(事务不一致),转账之后B变成0元,A也是0元,而C是100元,总量变成了100元,这就是不一致了。

  3. 隔离性中有隔离级别,其有四个等级,事务的隔离性可以阻止数据的脏读、幻读、重复读

    • Read-Uncommitted 0 无隔离级别,将会导致脏读

    • Read-Committed 1 隔离级别为1,可以避免脏读,但会重复读和幻读

    • Repeateable-Read 2 隔离级别为2,可以避免脏读、重复读,但会有幻读

    • Serializable 3 隔离级别最高,所有事务串行执行,可以避免脏读、重复读、幻读

      • 隔离级别越高,越能保证数据的完整和一致性,但对并发的影响也越大
      • 大多数数据库默认隔离级别为Read-Committed,比如SqlServer、Oracle
      • 少数数据库默认隔离级别为Repeateable-Read,比如MySQL InnoDB

      其中最高级别的隔离级别(Serializable)不推荐使用,将导致事务执行效率缓慢,因为每个事务都将一个一个串行执行。

      扫描二维码关注公众号,回复: 4392353 查看本文章
  4. 持久性很好理解,就是一旦事务提交,数据将持久化保存在磁盘中,就算服务器挂了,数据一样也都会持久化保存。

Spring封装了事务的所有操作,在我们日常生产环境中,只需要使用声明式事务例如打一个注解@Transaction就可以使用事务,或者也可以使用配置文件的方式来配置事务,就像AOP那样配置需要执行事务的方法即可,这种方式侵入性最低。那么,Spring是怎样实现事务的呢?这就是接下来要讲的,Spring的事务功能建立在AOP的基础上,而AOP功能又建立在IOC的基础之上,这里扯远了,所以,如果有AOP的基础,理解Spring中的事务管理将会很容易。

Spring事务基本原理与传播属性

Spring在很多地方其实都不是在重复造轮子,他只是封装了一下现有的技术,例如事务。底层对事务的管理也都是在数据库连接对象Connection上做文章,最后事务的提交、回滚等等都会交给Connection对象去做,而Spring只负责封装操作事务的过程。

Spring中的传播属性

首先先说一下传播属性,什么是事务的传播呢?假设一个事务方法调用了另一个事务方法,需要使用事务的传播属性去控制它。对于传播属性,网上也有一堆解释,这里只作简要介绍。

  • PROPAGATION_REQUIRED:支持当前存在事务,如果当前没有事务,就新建一个,如果当前有事务,就加入原事务,这是Spring默认的事务传播属性。
  • PROPAGATION_REQUIRES_NEW:如果当前存在事务,将此事务挂起,自己在新建一个事务,所以如果在这个传播属性外还有事务的话,两者事务是不一样的(将会存在两个事务),如果内层这个NEW属性抛出异常,外层事务如果CATCH住了,内层将会回滚而外层事务照样进行。
  • PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就不以事务方式运行。
  • PROGATION_MANDATORY:一定要在事务中运行,调用此方法必须原先就有一个事务,否则运行时抛异常。
  • PROGATION_NOT_SUPPORTED:以非事务方式执行,如果之前有事务,将之前事务挂起,此方法内无事务执行。
  • PROPAGATION_NEVER:以非事务方式执行,如果之前有事务就抛异常。
  • PROPAGATION_NESTED:嵌套事务(曾经我把这个传播属性与REEQUIRES_NEW混淆在一起了,其后会讲解两者到底有什么不同),如果之前有事务,将作为之前事务的子事务,如果之前没事务,将新建一个事务执行,这个传播属性可以创建SavePoint(可以回滚的保存点)。

Spring事务的基本原理

开头说到,Spring中的事务是基于AOP做的,也就是说,Spring会将其Bean做一次动态代理,实际执行拥有事务的方法时其实执行的是一个代理类,方法被代理到invoke(如果是JDK动态代理)中执行增强器,这里事务的增强器是TransactionInterceptor,主要的事务逻辑将在这个类的invoke方法中展开。

深入源码剖析Spring事务的实现原理

事务配置的起始点(配置文件开启事务)

<aop:aspectj-autoproxy proxy-target-class="true" />

<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource">
        <ref bean="dataSource" />
    </property>
</bean>	

事务管理器的作用下面会讲到,这里先来解析这个标签到底做了什么事。

自定义标签

谈到自定义标签,这是大多数对Spring的扩展的基础(起始点)。这里的<aop/>标签是一个自定义标签(关于Spring中自定义标签如何使用自行百度,这里不多赘述,有关于自定义标签改天我将另开一篇文章介绍),它会将AnnotationDrivenBeanDefinitionParser这个解析类注册进Spring中,在IOC载入过程中调用其parse方法。

public BeanDefinition parse(Element element, ParserContext parserContext) {
    registerTransactionalEventListenerFactory(parserContext);
    String mode = element.getAttribute("mode");
    if ("aspectj".equals(mode)) {
        // mode="aspectj"
        registerTransactionAspect(element, parserContext);
    }
    else {
        // mode="proxy"
        AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
    }
    return null;
}

如果没有设置标签中 mode属性,将会使用默认代理模式,这里只分析mode=“proxy”的情况。

		public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
            //向IOC注册InfrastructureAdvisorAutoProxyCreator这个类型的Bean
			AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);

			String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
			if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
				Object eleSource = parserContext.extractSource(element);

				// Create the TransactionAttributeSource definition.
                // 创建AnnotationTransactionAttributeSource类型的Bean
				RootBeanDefinition sourceDef = new RootBeanDefinition(
		"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
				sourceDef.setSource(eleSource);
				sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

				// Create the TransactionInterceptor definition.
                // 创建TransactionInterceptor类型的Bean
				RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
				interceptorDef.setSource(eleSource);
				interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				registerTransactionManager(element, interceptorDef);
				interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
				String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);

				// Create the TransactionAttributeSourceAdvisor definition.
                // 创建BeanFactoryTransactionAttributeSourceAdvisor类型的Bean
				RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
				advisorDef.setSource(eleSource);
				advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
                // 将上面AnnotationTransactionAttributeSource类型Bean注入进上面的Advisor
				advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
                // 将上面TransactionInterceptor类型Bean注入进上面的Advisor
				advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
				if (element.hasAttribute("order")) {
					advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
				}
				parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
				// 将上面三个Bean注册进IOC中
				CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
				compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
				compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
				compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
				parserContext.registerComponent(compositeDef);
			}
		}

这段代码只需要看我给的注释,有兴趣可以全部看下来。这里分别是注册了三个Bean,和一个InfrastructureAdvisorAutoProxyCreator,其中三个Bean支撑了整个事务的功能。

我们首先需要回顾一下AOP的原理,AOP中有一个 Advisor 存放在代理类中,而Advisor中有advisepointcut信息,每次执行被代理类的方法时都会执行代理类的invoke(如果是JDK代理)方法,而invoke方法会根据advisor中的pointcut动态匹配这个方法需要执行的advise链,遍历执行advise链,从而达到AOP切面编程的目的。

  1. BeanFactoryTransactionAttributeSourceAdvisor:首先看这个类的继承结构,可以看到这个类其实是一个Advisor,其实由名字也能看出来,类中有几个关键地方注意一下,在之前的注册过程中,将两个属性注入进这个Bean中:

    // 将上面AnnotationTransactionAttributeSource类型Bean注入进上面的Advisor
    advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
    // 将上面TransactionInterceptor类型Bean注入进上面的Advisor
    advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
    

    那么它们被注入成什么了呢?进入BeanFactoryTransactionAttributeSourceAdvisor一看便知。

    @Nullable
    private TransactionAttributeSource transactionAttributeSource;
    

    在其父类中有属性:

    @Nullable
    private String adviceBeanName;
    

    也就是说,这里先将上面的TransactionInterceptor的BeanName传入到Advisor中,然后将AnnotationTransactionAttributeSource这个Bean注入到Advisor中,那么这个Source Bean有什么用呢?可以继续看看BeanFactoryTransactionAttributeSourceAdvisor的源码。

    private final TransactionAttributeSourcePointcut pointcut = new 	TransactionAttributeSourcePointcut() {
        @Override
        @Nullable
        protected TransactionAttributeSource getTransactionAttributeSource() {
            return transactionAttributeSource;
        }
    };
    

    看到这里应该明白了,这里的Source是提供了pointcut信息,作为存放事务属性的一个类注入进Advisor中,到这里应该知道注册这三个Bean的作用了吧?首先注册pointcut、advise、advisor,然后将pointcut和advise注入进advisor中,在之后动态代理的时候会使用这个Advisor去寻找每个Bean是否需要动态代理(取决于是否有开启事务),因为Advisor有pointcut信息。

  2. InfrastructureAdvisorAutoProxyCreator:在方法开头,首先就调用了AopNamespeceUtils去注册了这个Bean,那么这个Bean是干什么用的呢?还是先看看这个类的结构。这个类继承了AbstractAutoProxyCreator,看到这个名字,熟悉AOP的话应该已经知道它是怎么做的了吧?其次这个类还实现了BeanPostProcessor接口,凡事实现了这个BeanPost接口的类,我们首先关注的就是它的postProcessAfterInitialization方法,这里在其父类也就是刚刚提到的AbstractAutoProxyCreator这里去实现。(这里需要知道Spring容器初始化Bean的过程,关于BeanPostProcessor的使用我会另开一篇讲解。如果不知道只需了解如果一个Bean实现了BeanPostProcessor接口,当所有Bean实例化且依赖注入之后初始化方法之后会执行这个实现Bean的postProcessAfterInitialization方法)

深入源码分析代理流程

这里将分析InfrastructureAdvisorAutoProxyCreator是如何对Bean进行代理的。下面是代理入口:

   /**
   * Create a proxy with the configured interceptors if the bean is
   * identified as one to proxy by the subclass.
   * @see #getAdvicesAndAdvisorsForBean
   */
   @Override
   public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
       if (bean != null) {
           // 这里将bean的class与beanName结合做一个cacheKey
           Object cacheKey = getCacheKey(bean.getClass(), beanName);
           if (!this.earlyProxyReferences.contains(cacheKey)) {
               	//如果需要,将会代理这个bean
           		return wrapIfNecessary(bean, beanName, cacheKey);
           	}
           }
       return bean;
   }
   protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
       	// 如果处理过这个bean的话直接返回
   		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
   			return bean;
   		}
       	// 之后如果Bean匹配不成功,会将Bean的cacheKey放入advisedBeans中
       	// value为false,所以这里可以用cacheKey判断此bean是否之前已经代理不成功了
   		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
   			return bean;
   		}
       	// 这里会将Advise、Pointcut、Advisor类型的类过滤,直接不进行代理,return
   		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
               // 这里即为不成功的情况,将false放入Map中
   			this.advisedBeans.put(cacheKey, Boolean.FALSE);
   			return bean;
   		}
   
   		// Create proxy if we have advice.
       	// 这里是主要验证的地方,传入Bean的class与beanName去判断此Bean有哪些Advisor
   		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
       	// 如果有相应的advisor被找到,则用advisor与此bean做一个动态代理,将这两个的信息
       	// 放入代理类中进行代理
   		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;
   		}
   		// 如果此Bean没有一个Advisor匹配,将返回null也就是DO_NOT_PROXY
       	// 也就是会走到这一步,将其cacheKey,false存入Map中
   		this.advisedBeans.put(cacheKey, Boolean.FALSE);
       	// 不代理直接返回原bean
   		return bean;
   	}

这里需要关注的是getAdvicesAndAdvisorsForBean这个方法,其去找到了Bean对应的Advisor:

   @Override
   @Nullable
   protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
       List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
       // 找不到advisor就返回空
       if (advisors.isEmpty()) {
           return DO_NOT_PROXY;
       }
       return advisors.toArray();
   }

这里需要关注的是findEligibleAdvisors这个方法:

   protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
       // 寻找所有的Advisor
       List<Advisor> candidateAdvisors = findCandidateAdvisors();
       // 根据所有的advisor筛选出此bean可以用的advisor
       List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
       extendAdvisors(eligibleAdvisors);
       if (!eligibleAdvisors.isEmpty()) {
           // 这里会对找到的advisor做一次sort
           eligibleAdvisors = sortAdvisors(eligibleAdvisors);
       }
       return eligibleAdvisors;
   }

进入寻找所有Advisor方法看看:

protected List<Advisor> findCandidateAdvisors() {
    Assert.state(this.advisorRetrievalHelper != null, "No 			BeanFactoryAdvisorRetrievalHelper available");
    return this.advisorRetrievalHelper.findAdvisorBeans();
}

这里委托了一个Helper类去寻找:

	/**
	 * Find all eligible Advisor beans in the current bean factory,
	 * ignoring FactoryBeans and excluding beans that are currently in creation.
	 * @return the list of {@link org.springframework.aop.Advisor} beans
	 * @see #isEligibleBean
	 */
	public List<Advisor> findAdvisorBeans() {
		// Determine list of advisor bean names, if not cached already.
		String[] advisorNames = null;
		synchronized (this) {
			advisorNames = this.cachedAdvisorBeanNames;
			if (advisorNames == null) {
				// Do not initialize FactoryBeans here: We need to leave all regular beans
				// uninitialized to let the auto-proxy creator apply to them!
                // 从BeanFactory中寻找是Advisor类的BeanName出来
				advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
						this.beanFactory, Advisor.class, true, false);
				this.cachedAdvisorBeanNames = advisorNames;
			}
		}
        // 没找到返回空
		if (advisorNames.length == 0) {
			return new LinkedList<>();
		}

		List<Advisor> advisors = new LinkedList<>();
		for (String name : advisorNames) {
			if (isEligibleBean(name)) {
				// 略...
					try {
                        // 走到这里BeanName就不是空的了,这里获取Advisor类型的Bean
						advisors.add(this.beanFactory.getBean(name, Advisor.class));
					}
					catch (BeanCreationException ex) {
						// 略...
					}
				}
			}
		}
		return advisors;
	}

我特意调试了一下,可以看到这里从beanFactory中获取了Advisor这个Bean,而这个Bean恰恰就是我们上面提到的,在自定义标签中注册的那个Bean BeanFactoryTransactionAttributeSourceAdvisor


获取到Advisor之后,进入方法findAdvisorsThatCanApply查询是否可以应用在此时Bean上:

	/**
	 * Search the given candidate Advisors to find all Advisors that
	 * can apply to the specified bean.
	 * @param candidateAdvisors the candidate Advisors
	 * @param beanClass the target's bean class
	 * @param beanName the target's bean name
	 * @return the List of applicable Advisors
	 * @see ProxyCreationContext#getCurrentProxiedBeanName()
	 */
	protected List<Advisor> findAdvisorsThatCanApply(
			List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

		ProxyCreationContext.setCurrentProxiedBeanName(beanName);
		try {
			return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
		}
		finally {
			ProxyCreationContext.setCurrentProxiedBeanName(null);
		}
	}
	/**
	 * Determine the sublist of the {@code candidateAdvisors} list
	 * that is applicable to the given class.
	 * @param candidateAdvisors the Advisors to evaluate
	 * @param clazz the target class
	 * @return sublist of Advisors that can apply to an object of the given class
	 * (may be the incoming List as-is)
	 */
	public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		List<Advisor> eligibleAdvisors = new LinkedList<>();
        // 这里先遍历所以的Advisor,看是不是引介增强
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) 			{	// 如果是引介增强,先处理
				eligibleAdvisors.add(candidate);
			}
		}
		boolean hasIntroductions = !eligibleAdvisors.isEmpty();
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor) {
				// already processed
                // 引介增强已经被处理过了
				continue;
			}
            // 真正验证的地方,合格则放入List中
			if (canApply(candidate, clazz, hasIntroductions)) {
				eligibleAdvisors.add(candidate);
			}
		}
		return eligibleAdvisors;
	}
	/**
	 * Can the given advisor apply at all on the given class?
	 * <p>This is an important test as it can be used to optimize out a advisor for a class.
	 * This version also takes into account introductions (for IntroductionAwareMethodMatchers).
	 * @param advisor the advisor to check
	 * @param targetClass class we're testing
	 * @param hasIntroductions whether or not the advisor chain for this bean includes
	 * any introductions
	 * @return whether the pointcut can apply on any method
	 */
	public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
		if (advisor instanceof IntroductionAdvisor) {
			return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
		}
        // 我们的事务Advisor是PointcutAdvisor,进入此方法
		else if (advisor instanceof PointcutAdvisor) {
			PointcutAdvisor pca = (PointcutAdvisor) advisor;
            // 这里将Advisor中的pointcut取出,与目标Bean进行匹配,返回匹配结果
			return canApply(pca.getPointcut(), targetClass, hasIntroductions);
		}
		else {
			// It doesn't have a pointcut so we assume it applies.
			return true;
		}
	}

看到这里也大致应证了我前面所说的,这里会利用Advisor这个bean中的pointcut与每个bean进行比对,如果合适pointcut,将会匹配成功,这个bean就会被代理,代理对象中会存放Advisor属性。

总结

到这里,大致介绍完Spring是如何进行事务了,其实现原理源自与自定义标签,而开启自定义标签之后会注册三个关于Advisor的Bean,和一个BeanPostProssor,当Spring中有BeanPostProssor时,会在每个Bean实例化与依赖注入之后执行BeanPostProssorpostProcessAfterInitialization方法,在这个方法中,会对Bean进行验证是否需要进行代理,如果需要则将上面的Advisor与此Bean一起去交给动态代理工厂做一个代理,返回代理类给IOC容器,如果不需要进行代理直接返回原Bean,达到了事务的效果。Advisor中的advice是事务功能实现的关键类,也就是自定义标签注册的Bean中叫做TransactionInterceptor的这个类,由于篇幅问题将放到下一篇来讲,同时下一篇文章也会介绍事务的传播特性使用场景与区别,透过事务本质看问题。

猜你喜欢

转载自blog.csdn.net/qq_41737716/article/details/84849995