Spring 中 Transactional 注解原理

栏目: Java · 发布时间: 6年前

内容简介:利用 Spring 框架可以很容易的使用注解的方式来使用事务,为我们的开发带来了巨大的便利,这种便利的实现是通过 Spring 本身的一系列机制来实现的,主要包含动态代理和 Spring Bean 的加载过程。本文将深入源码,揭开层层面纱…我们只需要在对应的方法上使用为何不会生效?是因为这样的调用不会经过 Spring 的代理,无法通过 Spring 的 advisor 来拦截数据库操作请求。

利用 Spring 框架可以很容易的使用注解的方式来使用事务,为我们的开发带来了巨大的便利,这种便利的实现是通过 Spring 本身的一系列机制来实现的,主要包含动态代理和 Spring Bean 的加载过程。本文将深入源码,揭开层层面纱…

Spring @Transactional 的使用

@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void methodInTransaction() {
    // 对数据库的一些操作
}

我们只需要在对应的方法上使用 @Transactional 注解即可让这个方法在事务中执行。这里需要注意的是,如果是在一个类中的两个方法,事务是不会生效的。举例:

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * Created by zhangbo on 2019-02-28.
 */
public class TransactionTest {
    public void methodNotIntransaction() {
        this.methodInTransaction(); // 此时被调用的方法 methodInTransaction 的事务并不会生效
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void methodInTransaction() {
        // 对数据库的一些操作
    }
}

为何不会生效?是因为这样的调用不会经过 Spring 的代理,无法通过 Spring 的 advisor 来拦截数据库操作请求。

Spring BeanPostProcessor

首先我们来了解一下 Spring Bean 的生命周期

  1. 调用InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
  2. bean实例化
  3. 调用InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation(Object bean, String beanName)
  4. 调用InstantiationAwareBeanPostProcessor的postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
  5. bean注入properties
  6. 分别调用BeanNameAware,BeanClassLoaderAware,BeanFactoryAware中的方法
  7. 调用BeanPostProcessor的postProcessBeforeInitialization(Object bean, String beanName)
  8. 调用InitializingBean的afterPropertiesSet方法
  9. 调用自定义初始化方法
  10. 调用BeanPostProcessor的postProcessAfterInitialization(Object bean, String beanName)
  11. 调用DisposableBean的destroy()方法
  12. 调用自定义销毁方法

作者:土豆肉丝盖浇饭

链接: https://www.jianshu.com/p/6d5c58168493

来源:简书

简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

通过上面的流程我们可以看到,BeanPostProcessor 中的两个方法 postProcessBeforeInitializationpostProcessAfterInitialization 分别在 bean 调用 init 方法前后调用。其中对于对象的代理就是在 postProcessAfterInitialization 方法中完成的,用代理的 bean 来替换原来的 bean

默认情况下, BeanPostProcessor 的职能是通过默认实现类 DefaultAdvisorAutoProxyCreator 实现的,类 DefaultAdvisorAutoProxyCreator 继承自 AbstractAdvisorAutoProxyCreator 该类的继承关系如下图

Spring 中 Transactional 注解原理

DefaultAdvisorAutoProxyCreator 如何代理被 @Transactional 注解的方法所属类

来看看 AbstractAutoProxyCreator 中发生了什么

/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
// 类 AbstractAutoProxyCreator
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (!this.earlyProxyReferences.contains(cacheKey)) {
            return wrapIfNecessary(bean, beanName, cacheKey); // 主要逻辑在这里
        }
    }
    return bean;
}

跟进 wrapIfNecessary 方法

/**
* Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
* @param bean the raw bean instance
* @param beanName the name of the bean
* @param cacheKey the cache key for metadata access
* @return a proxy wrapping the bean, or the raw bean instance as-is
*/
// 类 AbstractAutoProxyCreator
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // Create proxy if we have advice.
    // 查找 advice 从而创建代理类
    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;
    }

    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}
// AbstractAdvisorAutoProxyCreator 类
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
    Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    if (advisors.isEmpty()) {
        return DO_NOT_PROXY;
    }
    return advisors.toArray();
}
/**
* Find all eligible Advisors for auto-proxying this class.
* @param beanClass the clazz to find advisors for
* @param beanName the name of the currently proxied bean
* @return the empty List, not {@code null},
* if there are no pointcuts or interceptors
* @see #findCandidateAdvisors
* @see #sortAdvisors
* @see #extendAdvisors
*/

// AbstractAdvisorAutoProxyCreator 类
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    // 获取 候选 advisor 
    // BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Advisor.class, true, false);
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 筛选 可用的 advisor
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    
    // 此处会获取名称为org.springframework.transaction.interceptor.TransactionInterceptor#0的拦截器
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

我们来看看生成的动态类是什么样子的?

Spring 中 Transactional 注解原理

其中有一个 advisor 为

adviceBeanName:org.springframework.transaction.interceptor.TransactionInterceptor#0

TransactionInterceptor 类

我们此时来看看 org.springframework.transaction.interceptor.TransactionInterceptor 里究竟是如何执行 SQL 语句的。我们需要关注的方法为 invoke 方法

@Override
public Object invoke(final 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, new InvocationCallback() {
        @Override
        public Object proceedWithInvocation() throws Throwable {
            return invocation.proceed();
        }
    });
}

查看 invokeWithinTransaction 方法

// TransactionAspectSupport.java
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
		throws Throwable {

	// If the transaction attribute is null, the method is non-transactional.
	final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
	final PlatformTransactionManager tm = determineTransactionManager(txAttr);
	final String joinpointIdentification = methodIdentification(method, targetClass);

    // txAttr(事务属性)为空或者tm(事务管理器)为空时,是声明式事务
	if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
		// Standard transaction demarcation with getTransaction and commit/rollback calls.
        // 获取该方法上事务的信息
		TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
		Object retVal = null;
		try {
			// This is an around advice: Invoke the next interceptor in the chain.
			// This will normally result in a target object being invoked.
			retVal = invocation.proceedWithInvocation();
		}
		catch (Throwable ex) {
			// target invocation exception
            // 事务回滚
			completeTransactionAfterThrowing(txInfo, ex);
			throw ex;
		}
		finally {
			cleanupTransactionInfo(txInfo);
		}
		commitTransactionAfterReturning(txInfo);
		return retVal;
	}

	else {
		// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
		try {
			Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
					new TransactionCallback<Object>() {
						@Override
						public Object doInTransaction(TransactionStatus status) {
							TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
							try {
								return invocation.proceedWithInvocation();
							}
							catch (Throwable ex) {
								if (txAttr.rollbackOn(ex)) {
									// A RuntimeException: will lead to a rollback.
									if (ex instanceof RuntimeException) {
										throw (RuntimeException) ex;
									}
									else {
										throw new ThrowableHolderException(ex);
									}
								}
								else {
									// A normal return value: will lead to a commit.
									return new ThrowableHolder(ex);
								}
							}
							finally {
								cleanupTransactionInfo(txInfo);
							}
						}
					});

			// Check result: It might indicate a Throwable to rethrow.
			if (result instanceof ThrowableHolder) {
				throw ((ThrowableHolder) result).getThrowable();
			}
			else {
				return result;
			}
		}
		catch (ThrowableHolderException ex) {
			throw ex.getCause();
		}
	}
}

至此,我们基本了解了 Spring 声明式事务的工作流程


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Visual Thinking

Visual Thinking

Colin Ware / Morgan Kaufmann / 2008-4-18 / USD 49.95

Increasingly, designers need to present information in ways that aid their audiences thinking process. Fortunately, results from the relatively new science of human visual perception provide valuable ......一起来看看 《Visual Thinking》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

随机密码生成器
随机密码生成器

多种字符组合密码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具