Spring源码解读:@Transactional原理(1)

本文深入探讨了Spring中@Transactional注解的工作机制。首先,启用事务管理需要在配置类上添加@EnableTransactionManagement。接着,AutoProxyRegistrar和ProxyTransactionManagementConfiguration被引入,通过AOP生成TransactionAdvisor。TransactionInterceptor作为通知,处理事务逻辑。pointCut在TransactionAttributeSourcePointcut中定义,用于判断方法是否需要事务管理。最后,@Transactional可以在方法、类甚至接口上声明,影响事务的生效范围。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

这篇文章来讲讲Spring的重要组成部分@Transactional注解是如何生效的

一、@Transactional的作用

写java的都知道,这个注解是用来给方法添加事务的,一般情况我们都是用在访问数据库的service的逻辑上。

二、@Transactional如何生效的

1.@EnableTransactionManagement

项目要使用@Transactional来管理事务,就必须要在Application类上添加@EnableTransactionManagement注解,来解析下该注解吧

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({TransactionManagementConfigurationSelector.class})
public @interface EnableTransactionManagement {
    boolean proxyTargetClass() default false;

    AdviceMode mode() default AdviceMode.PROXY;

    int order() default 2147483647;
}

太眼熟了啊喂,也有Import注解,那废话不多说,咱们来看看Import进来的类是个什么作用。

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
    public TransactionManagementConfigurationSelector() {
    }

    protected String[] selectImports(AdviceMode adviceMode) {
        switch(adviceMode) {
        // 默认情况下,adviceMode是PROXY,可以查看上面的注解源码
        case PROXY:
            return new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
        case ASPECTJ:
            return new String[]{this.determineTransactionAspectClass()};
        default:
            return null;
        }
    }

    private String determineTransactionAspectClass() {
        return ClassUtils.isPresent("javax.transaction.Transactional", this.getClass().getClassLoader()) ? "org.springframework.transaction.aspectj.AspectJJtaTransactionManagementConfiguration" : "org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration";
    }
}

至于selectImport的实现逻辑,可以参看我那篇讲解@EnableAutoConfiguration注解实现原理的文章。
简而言之:此处spring会把AutoProxyRegistrar和ProxyTransactionManagementConfiguration添加进容器,同时当成配置类解析一下。

2. AutoProxyRegistrar

public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	private final Log logger = LogFactory.getLog(getClass());

	/**
	 * 这个类会在configurationClassPostProcessor的postProcessBeanDefinitionRegistry
	 * 里面统一调用ImportBeanDefinitionRegistrar的registerBeanDefinitions时被调用
	 * 然后注册相应的BeanDefinition
	 */
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		boolean candidateFound = false;
		// 获取@EnableTransactionManagement所在配置类(XXXApplication)上的注解元信息
		Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
		// 遍历注解
		for (String annType : annTypes) {
			// 遍历XXXApplication上所有的注解类型,分别封装成candidate,
			// 可以理解为将注解中的属性转换成一个map
			AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
			if (candidate == null) {
				continue;
			}
			// 直接从map中获取属性
			Object mode = candidate.get("mode");
			Object proxyTargetClass = candidate.get("proxyTargetClass");
			// mode,代理模型,一般都是SpringAOP
			// proxyTargetClass,是否使用cglib代理,默认是false
			if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&Boolean.class == proxyTargetClass.getClass()) {
				// 注解中存在这两个属性,并且属性类型符合要求,表示找到了合适的注解
				candidateFound = true;
				// 实际上会往容器中注册一个InfrastructureAdvisorAutoProxyCreator
				// 至于InfrastructureAdvisorAutoProxyCreator的作用,后面再说
				if (mode == AdviceMode.PROXY) {
					AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
					if ((Boolean) proxyTargetClass) {
						// 默认情况下,此处逻辑不会走
						AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
						return;
					}
				}
			}
		}
	}

}

3 ProxyTransactionManagementConfiguration

public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
    public ProxyTransactionManagementConfiguration() {
    }

	// 注册了一个BeanFactoryTransactionAttributeSourceAdvisor
	// advisor就是一个绑定了切点的通知
	// 可以看到通知就是TransactionInterceptor
	// 在BeanFactoryTransactionAttributeSourceAdvisor中要创建pointCut
	// 切点会通过TransactionAttributeSource去解析@Transacational注解
	// 只会对有这个注解的方法进行拦截
	// AOP advisor 重要的两个东西 pointCut和 Advice 就都有了
    @Bean(
        name = {"org.springframework.transaction.config.internalTransactionAdvisor"}
    )
    @Role(2)
    public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
    	// 事务aop的通知advisor
        BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
        advisor.setTransactionAttributeSource(transactionAttributeSource);
        advisor.setAdvice(transactionInterceptor);
        if (this.enableTx != null) {
            advisor.setOrder((Integer)this.enableTx.getNumber("order"));
        }

        return advisor;
    }

	// 注册一个AnnotationTransactionAttributeSource
	// 这个类的主要作用是用来解析@Transacational注解
    @Bean
    @Role(2)
    public TransactionAttributeSource transactionAttributeSource() {
        return new AnnotationTransactionAttributeSource();
    }

	// 事务是通过AOP实现的,AOP的核心就是拦截器
	// 这里就是注册了实现事务需要的拦截器
    @Bean
    @Role(2)
    public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
        TransactionInterceptor interceptor = new TransactionInterceptor();
        interceptor.setTransactionAttributeSource(transactionAttributeSource);
        if (this.txManager != null) {
            interceptor.setTransactionManager(this.txManager);
        }

        return interceptor;
    }
}

3.1 advisor中的pointCut

在BeanFactoryTransactionAttributeSourceAdvisor中有个pointCut,这个pointCut的类型是TransactionAttributeSourcePointcut,在这个类里面有个matches方法是用来判断target类的方法在执行时是否需要使用该advisor的advice的。

@Override
	public boolean matches(Method method, Class<?> targetClass) {
		if (TransactionalProxy.class.isAssignableFrom(targetClass) ||
				PlatformTransactionManager.class.isAssignableFrom(targetClass) ||
				PersistenceExceptionTranslator.class.isAssignableFrom(targetClass)) {
			return false;
		}
		TransactionAttributeSource tas = getTransactionAttributeSource();
		//因为我们往advisor里传递了TransactionAttributeSource,所以tas不为空
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}

所以我们重点来看一下getTransactionAttribute方法

	/**
	 * // 获取事务对应的属性,实际上返回一个AnnotationTransactionAttributeSource
	 * // 之后再调用AnnotationTransactionAttributeSource的getTransactionAttribute
	 * // getTransactionAttribute:先从拦截的方法上找@Transactional注解
	 * // 如果方法上没有的话,再从方法所在的类上找,如果类上还没有的话尝试从接口或者父类上找
	 */
	@Override
	@Nullable
	public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		if (method.getDeclaringClass() == Object.class) {
			return null;
		}

		// First, see if we have a cached value.
		// 从缓存里找
		Object cacheKey = getCacheKey(method, targetClass);
		TransactionAttribute cached = this.attributeCache.get(cacheKey);
		if (cached != null) {
			// Value will either be canonical value indicating there is no transaction attribute,
			// or an actual transaction attribute.
			if (cached == NULL_TRANSACTION_ATTRIBUTE) {
				return null;
			}
			else {
				return cached;
			}
		}
		else {
			// We need to work it out.
			// 此处是真正的解析
			TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
			// Put it in the cache.
			// 解析的结果缓存起来,如果为事务属性为null,也放入一个标志
			// 代表这个方法不需要进行事务管理
			if (txAttr == null) {
				this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
			}
			else {
				String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
				if (txAttr instanceof DefaultTransactionAttribute) {
					((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
				}
				if (logger.isTraceEnabled()) {
					logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
				}
				this.attributeCache.put(cacheKey, txAttr);
			}
			return txAttr;
		}
	}

再来看看真正判断方法是否要启用advisor的逻辑

@Nullable
	protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		// Don't allow no-public methods as required.
		// 默认情况下allowPublicMethodsOnly为true
		// 这意味着@Transactional如果放在非public方法上不会生效
		if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
			return null;
		}
		// The method may be on an interface, but we need attributes from the target class.
		// If the target class is null, the method will be unchanged.
		// method是接口中的方法
		// specificMethod是具体实现类的方法
		// 相当于根据接口获取到实现类的代理类的对应方法
		Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

		// First try is the method in the target class.
		// 首先从方法上找@Transactional注解
		TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
		if (txAttr != null) {
			return txAttr;
		}

		// Second try is the transaction attribute on the target class.
		// 其次从方法的类(目标类)上找@Transactional注解
		txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
		if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
			return txAttr;
		}

		//到接口和接口中的方法上找注解
		if (specificMethod != method) {
			// Fallback is to look at the original method.
			txAttr = findTransactionAttribute(method);
			if (txAttr != null) {
				return txAttr;
			}
			// Last fallback is the class of the original method.
			txAttr = findTransactionAttribute(method.getDeclaringClass());
			if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
				return txAttr;
			}
		}

		return null;
	}

由此可见,在方法或者targetClass上加@Transactional都可以,甚至在接口或者接口的方法上加@Transactional也可以。

总结

小结

  1. 通过对@EnableTransactionManagement的解析,来探寻@Transactional是如何基于AOP原理生效的。
    主要是生成了一个BeanFactoryTransactionAttributeSourceAdvisor。

AOP

  1. 针对AOP中重要的pointCut。pointCut定义Advisor是否可以针对targetClass的方法使用时进行启用,在BeanFactoryTransactionAttributeSourceAdvisor中定义了TransactionAttributeSourcePointcut类型的pointCut,该pointCut中的matches方法说明了,只要targetClass的method上加了@Transactional或者targetClass上加了@Transactional,甚至接口类和方法上加了@Transactional,都可以在method执行时,匹配上该advisor
  2. 针对AOP中重要的Advice,用TransactionInterceptor来实现的,至于具体的执行逻辑,其实就是其内部的invoke方法,具体执行的是invokeWithinTransaction,这个值得专门写一篇文章来讲

okay,that’s all
下一篇主要讲TransactionInterceptor的运行逻辑,点击这里查看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值