(十)Spring事务处理 - IoC容器的事务处理源码分析

Spring事务处理主要分以下三个主要的过程:

(1)读取和处理在Spring IoC容器中配置的事务处理属性,并转化为Spring事务处理所需要的内部数据结构。

(2)Spring事务处理模块实现的统一的事务处理过程。这个通用的事务处理过程包括:处理事务配置属性;事务配置属性与线程绑定等。

(3)底层事务处理实现。Spring中底层事务处理的实现交由PlatformTransactionManager的具体实现类来实现,如DataSourceTransactionManager和HibernateTransactionManager等。

一、Spring管理事务处理的IoC容器—TransactionProxyFactoryBean

TransactionProxyFactoryBean是Spring中管理事务的IoC容器,它通过Spring的AOP功能来完成事务管理配置。TransactionProxyFactoryBean为Spring的事务处理的实现做准备工作,包括配置AOP的拦截器、通知器;同时向TransactionProxyFactoryBean注入事务处理器和事务处理属性等。TransactionProxyFactoryBean源码如下:

public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBean
		implements BeanFactoryAware {
	//通过AOP发挥作用的事务拦截器
	private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
	//事务的AOP切入点
	private Pointcut pointcut;
	//通过Spring IoC容器依赖注入的PlatformTransactionManager事务管理器
	public void setTransactionManager(PlatformTransactionManager transactionManager) {
	this.transactionInterceptor.setTransactionManager(transactionManager);
	}
	//通过依赖注入设置事务属性,以Properties形式存放的事务属性的key是方法名,
	//value是事务属性描述
	public void setTransactionAttributes(Properties transactionAttributes) {
	this.transactionInterceptor.setTransactionAttributes(transactionAttributes);
	}
	//通过依赖注入设置事务属性源,通过事务属性源可以找到需要使用的事务属性
	public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
	this.transactionInterceptor.setTransactionAttributeSource(transactionAttributeSource);
	}
	//通过依赖注入设置事务切入点,事务切入点根据触发条件调用事务拦截器
	public void setPointcut(Pointcut pointcut) {
		this.pointcut = pointcut;
	}
	//为事务拦截器设置管理事务的容器
	public void setBeanFactory(BeanFactory beanFactory) {
		this.transactionInterceptor.setBeanFactory(beanFactory);
	}
//创建Spring AOP事务处理的通知器Advisor
	protected Object createMainInterceptor() {
		//调用事务拦截器的方法,检查必需的属性是否设置
		this.transactionInterceptor.afterPropertiesSet();
		//如果在Spring配置中设置了事务切入点
		if (this.pointcut != null) {
			//使用Spring默认的通知器封装事务切入点和事务拦截器
			return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);
		}
		//如果在Spring配置中没有设置事务切入点
		else {
			//使用TransactionAttributeSourceAdvisor封装默认的事务切入点
			return new TransactionAttributeSourceAdvisor(this.transactionInterceptor);
		}
	}
} 

Spring的事务处理IoC容器TransactionProxyFactoryBean中主要通过依赖注入完成事务切入点和事务拦截器的配置,最重要的功能是通过createMainInterceptor()方法为事务切入点和事务拦截器创建AOP事务通知器。

TransactionProxyFactoryBean继承了AbstractSingletonProxyFactoryBean类,作为Spring事务管理IoC容器,其getObject()方法和IoC容器初始化完成之后回调的afterPropertiesSet()方法均是在其父类AbstractSingletonProxyFactoryBean中实现的,我们接下来分析AbstractSingletonProxyFactoryBean中事务处理相关源码的实现。

二、AbstractSingletonProxyFactoryBean创建配置事务

AbstractSingletonProxyFactoryBean实现了FactoryBean和InitializingBean接口,Spring IoC容器最核心的getObject()和afterPropertiesSet()方法均是在该类中实现,AbstractSingletonProxyFactoryBean创建和配置事务相关的方法源码如下:

//获取Spring事务代理工厂(ProxyFactory)
public Object getObject() {
		if (this.proxy == null) {
			throw new FactoryBeanNotInitializedException();
		}
		return this.proxy;
	}
//InitializingBean接口的实现方法,IoC容器初始化完成之后的回调方法
public void afterPropertiesSet() {
		//事务的目标对象不能为空
		if (this.target == null) {
			throw new IllegalArgumentException("Property 'target' is required");
		}
		//事务目标对象必须是Bean引用,不能是Bean名称
		if (this.target instanceof String) {
			throw new IllegalArgumentException("'target' needs to be a bean reference, not a bean name as value");
		}
		//如果代理类加载器为null,则使用默认的类加载器作用代理类加载器
		if (this.proxyClassLoader == null) {
			this.proxyClassLoader = ClassUtils.getDefaultClassLoader();
		}
//创建代理工厂,Spring事务管理容器TransactionProxyFactoryBean通过//ProxyFactory完成AOP的基本功能,ProxyFactory提供事务代理对象,并将事务拦//截器设置为事务目标对象方法的拦截器
		ProxyFactory proxyFactory = new ProxyFactory();
		//如果在事务拦截器之前配置了额外的拦截器
		if (this.preInterceptors != null) {
			//将这些事务之前的额外拦截器添加到通知器中
			for (Object interceptor : this.preInterceptors) {
	proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(interceptor));
			}
		}
//加入Spring AOP事务处理通知器,createMainInterceptor()方法
//由子类TransactionProxyFactoryBean提供实现	proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(createMainInterceptor()));
		//如果在事务拦截器之后配置了额外拦截器
		if (this.postInterceptors != null) {
			//将这些事务之后的额外拦截器添加到通知器中
			for (Object interceptor : this.postInterceptors) {
	proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(interceptor));
			}
		}
		//从当前容器中复制事务AOP相关配置到ProxyFactory中
		proxyFactory.copyFrom(this);
		//创建AOP的目标源
		TargetSource targetSource = createTargetSource(this.target);
		//为ProxyFactory设置AOP目标源
		proxyFactory.setTargetSource(targetSource);
		//如果事务配置使用了代理接口
		if (this.proxyInterfaces != null) {
			//为ProxyFactory设置代理接口
			proxyFactory.setInterfaces(this.proxyInterfaces);
		}
		//如果事务代理不是直接应用于目标类或者接口
		else if (!isProxyTargetClass()) {
			//将目标源的所有接口都设置为ProxyFactory的接口
			proxyFactory.setInterfaces(
	ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass(), this.proxyClassLoader));
		}
		//ProxyFactory对象根据给定的类加载器创建事务代理对象
		//具体的创建过程我们在Spring的AOP源码分析中已经分析过,Spring根据是否
		//实现接口而分别调用JDK动态代理或者CGLIB方式创建AOP代理对象
		this.proxy = proxyFactory.getProxy(this.proxyClassLoader);
	}

当Spring事务IoC容器初始化完成之后,事务容器回调afterPropertiesSet()方法创建事务AOP代理对象。

三、TransactionAttributeSourceAdvisor读取Spring事务处理配置

在创建Spring事务的核心方法createMainInterceptor()中,根据给定的事务拦截器创建事务属性源通知器TransactionAttributeSourceAdvisor,事务属性源通知器的核心源码如下:

//事务拦截器
private TransactionInterceptor transactionInterceptor;
//事务属性源切入点,一个实现事务属性源切入点接口的匿名内部类
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
	//实现事务属性源切入点接口的获取事务属性源方法
	protected TransactionAttributeSource getTransactionAttributeSource() {
			//通过事务拦截器获取事务的配置属性
			return (transactionInterceptor != null ? transactionInterceptor.getTransactionAttributeSource() : null);
		}
	};
//事务属性源通知器构造方法
public TransactionAttributeSourceAdvisor(TransactionInterceptor interceptor) {
		setTransactionInterceptor(interceptor);
	}
//设置事务拦截器
public void setTransactionInterceptor(TransactionInterceptor interceptor) {
		this.transactionInterceptor = interceptor;
	}

事务属性源通知器的核心功能是为Spring的事务IoC容器设置事务属性源切入点和事务拦截器。

四、事务切入点TransactionAttributeSourcePointcut匹配事务配置规则

事务切入点TransactionAttributeSourcePointcut在事务属性源通知器中作为匿名内部类,用于根据事务的配置匹配符合规则的方法,事务切入点的核心源码如下:

//匹配事务目标类的方法
public boolean matches(Method method, Class targetClass) {
		//获取事务属性源,getTransactionAttributeSource是一个抽象方法,在事务属性源通知器中实现
		TransactionAttributeSource tas = getTransactionAttributeSource();
		//返回指定类指定方法是否匹配事务属性
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}

事务属性源TransactionAttributeSource在事务拦截器TransactionInterceptor的父类事务切面支持TransactionAspectSupport中配置,源码如下:

//配置事务属性源
public void setTransactionAttributes(Properties transactionAttributes) {
		//使用名称匹配的事务属性源
		NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();
		tas.setProperties(transactionAttributes);
		this.transactionAttributeSource = tas;
	} 

Spring默认使用名称匹配事务属性源NameMatchTransactionAttributeSource读取和匹配事务属性。

五、NameMatchTransactionAttributeSource读取和匹配事务属性

名称匹配属性属性源从事务处理属性配置中读取事务的方法名和配置属性值,将得到的事务方法名和属性值保存到一个Map集合中,方法名作为key,事务属性值作为value。名称匹配事务属性源主要源码如下:

public class NameMatchTransactionAttributeSource implements TransactionAttributeSource, Serializable {
	……
//设置方法事务属性
public void setProperties(Properties transactionAttributes) {
		//创建事务属性解析器
		TransactionAttributeEditor tae = new TransactionAttributeEditor();
		//获取事务属性配置中所有属性名称
		Enumeration propNames = transactionAttributes.propertyNames();
		//遍历所有的事务属性
		while (propNames.hasMoreElements()) {
				//获取事务属性配置的方法名
			String methodName = (String) propNames.nextElement();
			//获取方法配置的事务属性值
			String value = transactionAttributes.getProperty(methodName);
			//解析和格式化事务属性值
			tae.setAsText(value);
			//获取解析和格式化之后的事务属性
			TransactionAttribute attr = (TransactionAttribute) tae.getValue();
			//将方法名和其对应的事务属性添加到集合中
			addTransactionalMethod(methodName, attr);
		}
	}
	//将方法名称和该方法配置的事务属性添加到Map集合中
	public void addTransactionalMethod(String methodName, TransactionAttribute attr) {
		if (logger.isDebugEnabled()) {
			logger.debug("Adding transactional method [" + methodName + "] with attribute [" + attr + "]");
		}
		this.nameMap.put(methodName, attr);
	}
	//获取给定类给定方法中配置的事务属性
	public TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass) {
		//获取方法名
		String methodName = method.getName();
		//从方法名—>事务属性Map集合中获取给定方法名的事务属性
		TransactionAttribute attr = this.nameMap.get(methodName);
		//如果在方法名—>事务属性Map集合中没有给定方法名的事务属性
		if (attr == null) {
			String bestNameMatch = null;
			//判断给定方法名称是否在方法名—>事务属性Map集合的key中
			for (String mappedName : this.nameMap.keySet()) {
				//如果给定的方法名在Map集合的key中匹配
				if (isMatch(methodName, mappedName) &&
						(bestNameMatch == null || bestNameMatch.length() <= mappedName.length())) {
					//获取匹配方法的事务属性
					attr = this.nameMap.get(mappedName);
					bestNameMatch = mappedName;
				}
			}
		}
		return attr;
	}
	//判断给定的方法名是否匹配,默认实现了"xxx*","*xxx"和"*xxx*"匹配检查
	protected boolean isMatch(String methodName, String mappedName) {
		return PatternMatchUtils.simpleMatch(mappedName, methodName);
	}
……
}

名称匹配事务属性源NameMatchTransactionAttributeSource主要在两个阶段发挥作用,在Spring事务IoC容器对事务配置读取解析时,事务容器调用名称匹配事务属性源的setProperties和addTransactionalMethod方法将方法名称和事务属性添加到Map集合中,当方法调用时,通过getTransactionAttribute方法获取方法所配置的事务属性。

六、事务拦截器TransactionInterceptor的实现

管理Spring事务的IoC容器TransactionProxyFactoryBean已经完成了事务配置的读取,设置好了事务拦截器和切入点。当应用调用被配置事务的方法时,首先通过getObject方法向Spring事务管理容器索取被被管理方法的事务属性,触发调用事务拦截器的拦截方法进行事务处理。

在对Spring AOP源码分析中关于AOP代理如何起作用时,我们知道Spring的AOP代理通过invoke回调方法对切入点方法进行拦截处理,这个invoke方法是AOP联盟的方法拦截器MethodInterceptor接口中定义的方法,用于对AOP代理对象的方法进行包装处理。事务拦截器TransactionInterceptor正是通过这个invoke拦截方法实现事务的拦截处理,源码如下:

//事务拦截器的拦截方法
public Object invoke(final MethodInvocation invocation) throws Throwable {
		//通过AOP获取事务的目标类
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
		//通过事务属性源TransactionAttributeSource读取事务的属性配置,即调用上面名称匹配
//事务属性源NameMatchTransactionAttributeSource的方法
		final TransactionAttribute txAttr =
	getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);
//获取Spring事务管理IoC容器配置的事务处理器
		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
		//获取目标类指定方法的事务连接点
		final String joinpointIdentification = methodIdentification(invocation.getMethod(), targetClass);
//区分不同类型的PlatformTransactionManager事务处理器,不同类型的事务处理器调用//方式不同。对CallbackPreferringPlatformTransactionManager,需要回调函数来//实现事务的创建和提交,对非CallbackPreferringPlatformTransactionManager来//说,则不需要使用回调函数来实现事务处理。
		//非CallbackPreferringPlatformTransactionManager类型的事务处理器
		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
			//创建事务,将当前事务状态和信息保存到TransactionInfo对象中
			TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
			Object retVal = null;
			try {
				//沿着拦截器链调用处理,使得最后目标对象的方法得到调用
				retVal = invocation.proceed();
			}
			catch (Throwable ex) {
				//在调用拦截器拦过程中出现异常,则根据事务配置进行提交或回滚处理
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			//清除与当前线程绑定的事务信息
			finally {
				cleanupTransactionInfo(txInfo);
			}
			//通过事务处理器来对事务进行提交
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}
		//CallbackPreferringPlatformTransactionManager类型的事务处理器
		else {
			//通过回调函数对事务进行处理
			try {
				//执行实现TransactionCallback接口的doInTransaction回调方法
				Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
						new TransactionCallback<Object>() {
							//实现TransactionCallback接口匿名内部类的回调方法
public Object doInTransaction(TransactionStatus status) {
	//创建和准备事务
								TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
								try {
									//沿着拦截器拦调用
									return invocation.proceed();
								}
								//拦截器链处理过程中产生异常
								catch (Throwable ex) {
									//如果事务对异常进行回滚处理
									if (txAttr.rollbackOn(ex)) {
										//如果异常时运行时异常,则事务回滚处理
									   if (ex instanceof RuntimeException) {
											throw (RuntimeException) ex;
										}
										//如果不是运行时异常,则提交处理
										else {
											throw new ThrowableHolderException(ex);
										}
									}
									//如果事务对异常不进行回滚处理
									else {
										//提交处理
										return new ThrowableHolder(ex);
									}
								}
								//清除当前线程绑定的事务信息
								finally {
									cleanupTransactionInfo(txInfo);
								}
							}
						});
				//对调用结果异常进行处理。
//如果是ThrowableHolder类型的异常,则转换为Throwable抛出
				if (result instanceof ThrowableHolder) {
					throw ((ThrowableHolder) result).getThrowable();
				}
				//如果不是ThrowableHolder类型的异常,则异常不做处理直接抛出
				else {
					return result;
				}
			}
			catch (ThrowableHolderException ex) {
				throw ex.getCause();
			}
		}
	}

通过上面对事务拦截器的拦截方法源码分析,我们可以看到Spring事务处理的基本工作流程:

(1)在调用方法时首先获取方法的事务属性配置,根据方法事务属性配置创建事务,获取Spring事务容器配置的事务处理器。

(2)调用具体的事务处理器对事务进行具体的处理。

(3)根据事务处理结果和事务处理过程中产生异常等进行提交或者回滚等处理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值