Spring 中 Transactional 注解原理

/ / 点击

利用 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该类的继承关系如下图

AbstractAutoProxyCreator继承关系

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;
}

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

Jietu20190228-174753@2x

其中有一个 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 声明式事务的工作流程


全文完。